|
| 1 | +# DaaS (crypto 50) |
| 2 | + |
| 3 | +###ENG |
| 4 | +[PL](#pl-version) |
| 5 | + |
| 6 | +In the task we get the address of the remote service and the [source code](DaaS.py). |
| 7 | +We also get a file with RSA-encrypted flag. |
| 8 | + |
| 9 | +``` |
| 10 | +flag = 0xc18b1d3b892e29863d8a6b46059995173635a3fd9f2ad877143a2d14ee736d8b12f9e735d6877a553312101eb757a0e3b3795bea88f2b4f72d1eb47ef6062a0dfd659892dfb2b98c70406e0c3e5e8624e81622b772d9e4183a29c9bf2f10ef15de3bfcb112a5f76688a146466db5a8e2dfe6679806c8e0b244458296efcba450 |
| 11 | +``` |
| 12 | + |
| 13 | +The remote service can perform RSA-decode for any input we want, apart from the flag itself. |
| 14 | + |
| 15 | +The RSA implementation is not using any padding, and therefore it is homomorphic, which is what we use to break the encryption. |
| 16 | +Homomorphic property means in this case that `rsa_encrypt(a*b) = rsa_encrypt(a)*rsa_encrypt(b)` and the same goes for decrypt, since both are doing exactly the same mathematical operation - modular power. |
| 17 | + |
| 18 | +RSA encryption is `ciphertext = plaintext^e (mod n)` and decryption is `plaintext = ciphertext^d (mod n)`. |
| 19 | + |
| 20 | +We cannot ask the server to decrypt the flag for us, but we can ask it to decrypt `int(flag)/2`, which means we will get the value `enc_flag_2 = (enc_flag/2)^d (mod n)`. |
| 21 | +We can then ask the server to decrypt value `2` for us, which means we will get `two = 2^d (mod n)` |
| 22 | + |
| 23 | +Now if we simply multiply those numbers (mod n) we will get: |
| 24 | + |
| 25 | +`enc_flag_2 * two = (enc_flag/2)^d (mod n) * 2^d (mod n) = ((enc_flag/2)^d * 2^d) mod n = enc_flag^d mod n = flag` |
| 26 | + |
| 27 | +So we just sent `flag/2` and `2` as inputs and then recovered flag with: |
| 28 | + |
| 29 | +```python |
| 30 | +def long_to_bytes(data): |
| 31 | + data = str(hex(data))[2:-1] |
| 32 | + return "".join([chr(int(data[i:i + 2], 16)) for i in range(0, len(data), 2)]) |
| 33 | + |
| 34 | +n = 0xcd67fc599866f87bc45ff87c1634aa144ee257c963ab2541052f3b38d22a11b255b0dd9318153699664b1007b7f38118df77f703909888c3930b73221c57828fc423a643b1eaf47f03d6c24b11d907f979dae4aa47347959c7c77bda8f9804dd95cc438d75ced522c7391a5d1432978440bfacc9939a33d6e6e058b15a084f99 |
| 35 | +enc_flag_2 = 0x120643f13ec8942b09296bb1e08c3b1608804771815e7a138560e6e5801cae4c073d5f88f3ced989743818a91290f3772614462f3fa6af7cdf5b534ccb031124656117714f7ae602016b9bd732f366be53c59501d393caba6fb12e38b5e55ffc57ccbb4ce3c7a3e2d344cf2a7e487d45c4e0c76e0cf5e8846efdce0955f81930 |
| 36 | +two = 0x3a997500f5c2e8cb21996f73cc3d05f58a8f6003fa2e97481dc09f04517ffbf6ef6585f415cb2ea95449ab7ced07443e1b330deeed169bb3d88088167a37434cf1d39ce5b639c1b99a18279f26b8f2e197c0a94a291a6d2efb42adf27d082791be6e589e62dfbc85afc882996a4a68d474f0c334ef29b5a953ec4fbcff52bd38 |
| 37 | + |
| 38 | +print(long_to_bytes((enc_flag_2 * two) % n)) |
| 39 | + |
| 40 | +``` |
| 41 | + |
| 42 | +Which gave `ECTF{Good job! You broke RSA!}` |
| 43 | + |
| 44 | +###PL version |
| 45 | + |
| 46 | +W zadaniu dostajemy adres zdalnego serwera oraz [kod źródłowy](DaaS.py). |
| 47 | +Dostajemy także plik z flagą zaszyfrowaną za pomocą RSA. |
| 48 | + |
| 49 | + |
| 50 | +``` |
| 51 | +flag = 0xc18b1d3b892e29863d8a6b46059995173635a3fd9f2ad877143a2d14ee736d8b12f9e735d6877a553312101eb757a0e3b3795bea88f2b4f72d1eb47ef6062a0dfd659892dfb2b98c70406e0c3e5e8624e81622b772d9e4183a29c9bf2f10ef15de3bfcb112a5f76688a146466db5a8e2dfe6679806c8e0b244458296efcba450 |
| 52 | +``` |
| 53 | + |
| 54 | +Serwer pozwala zdekodować za pomocą RSA dowolne dane, oprócz samej flagi. |
| 55 | + |
| 56 | +Implementacja RSA nie używa paddingu, co oznacza że operacje są homomorficzne, co pozwala nam na złamanie szyfrowania. |
| 57 | +Homomorfizm w tym kontekście oznacza, że `rsa_encrypt(a*b) = rsa_encrypt(a)*rsa_encrypt(b)` i analogicznie dla operacji deszyfrowania, ponieważ obie funkcje realizują tą samą operacje matematyczną - potęgowanie modularne. |
| 58 | + |
| 59 | +Szyfrowanie RSA to `ciphertext = plaintext^e (mod n)` a deszyfrowanie `plaintext = ciphertext^d (mod n)`. |
| 60 | + |
| 61 | +Nie możemy poprosić serwra o deszyfrowanie flagi, ale możemy poprosić o deszyfrowanie `int(flag)/2`, co oznacza że dostaniemy wartość `enc_flag_2 = (enc_flag/2)^d (mod n)`. |
| 62 | +Teraz możemy poprosić serwer o dekodowanie wartości `2`, co oznacza że dostaniemy `two = 2^d (mod n)`. |
| 63 | + |
| 64 | +Teraz jeśli pomnożymy te liczby (mod n) dostaniemy: |
| 65 | + |
| 66 | +`enc_flag_2 * two = (enc_flag/2)^d (mod n) * 2^d (mod n) = ((enc_flag/2)^d * 2^d) mod n = enc_flag^d mod n = flag` |
| 67 | + |
| 68 | +Więc wysyłamy do serwera `flag/2` oraz `2` a następnie odzyskujemy flagę przez: |
| 69 | + |
| 70 | +```python |
| 71 | +def long_to_bytes(data): |
| 72 | + data = str(hex(data))[2:-1] |
| 73 | + return "".join([chr(int(data[i:i + 2], 16)) for i in range(0, len(data), 2)]) |
| 74 | + |
| 75 | +n = 0xcd67fc599866f87bc45ff87c1634aa144ee257c963ab2541052f3b38d22a11b255b0dd9318153699664b1007b7f38118df77f703909888c3930b73221c57828fc423a643b1eaf47f03d6c24b11d907f979dae4aa47347959c7c77bda8f9804dd95cc438d75ced522c7391a5d1432978440bfacc9939a33d6e6e058b15a084f99 |
| 76 | +enc_flag_2 = 0x120643f13ec8942b09296bb1e08c3b1608804771815e7a138560e6e5801cae4c073d5f88f3ced989743818a91290f3772614462f3fa6af7cdf5b534ccb031124656117714f7ae602016b9bd732f366be53c59501d393caba6fb12e38b5e55ffc57ccbb4ce3c7a3e2d344cf2a7e487d45c4e0c76e0cf5e8846efdce0955f81930 |
| 77 | +two = 0x3a997500f5c2e8cb21996f73cc3d05f58a8f6003fa2e97481dc09f04517ffbf6ef6585f415cb2ea95449ab7ced07443e1b330deeed169bb3d88088167a37434cf1d39ce5b639c1b99a18279f26b8f2e197c0a94a291a6d2efb42adf27d082791be6e589e62dfbc85afc882996a4a68d474f0c334ef29b5a953ec4fbcff52bd38 |
| 78 | + |
| 79 | +print(long_to_bytes((enc_flag_2 * two) % n)) |
| 80 | + |
| 81 | +``` |
| 82 | + |
| 83 | +Co daje nam `ECTF{Good job! You broke RSA!}` |
0 commit comments