-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added more writeups, and made small adjustments to previous writeups …
…I submitted
- Loading branch information
1 parent
1a3c2f3
commit 04fba91
Showing
13 changed files
with
1,428 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Hash On Hash - 100 points | ||
|
||
There's a lot of hex strings here. Maybe they're hiding a message? [hexstrings](../files/HashOnHash.txt) | ||
|
||
### Solution | ||
###### Writeup by Valar Dragon | ||
|
||
|
||
The file hexstrings is a file with many lines of 32 chars of hex. | ||
I ignored the hint, and put the first few into the online hash cracker [CrackStation](https://crackstation.net/) | ||
|
||
From that you could see that they were all MD5 hashes of 1 letter! | ||
Then it was easy, | ||
I just wrote a script to make all the 256 1 character MD5's. | ||
Then iterate line by line and replace the lines with character that md5's to it. Concatenate the characters, and print the corresponding characters. | ||
|
||
``` | ||
$ python3 hexstringsSolver.py | ||
Im far too lazy to put anything meaningful here. Instead, here's some information about what you just solved. | ||
The MD5 algorithm is a widely used hash function producing a 128-bit hash value. Although MD5 was initially designed to be used as a cryptographic hash function, it has been found to suffer from extensive vulnerabilities. It can still be used as a checksum to verify data integrity, but only against unintentional corruption. | ||
Like most hash functions, MD5 is neither encryption nor encoding. It can be cracked by brute-force attack and suffers from extensive vulnerabilities as detailed in the security section below. | ||
MD5 was designed by Ronald Rivest in 1991 to replace an earlier hash function MD4.[3] The source code in RFC 1321 contains a "by attribution" RSA license. The abbreviation "MD" stands for "Message Digest." | ||
The security of the MD5 has been severely compromised, with its weaknesses having been exploited in the field, most infamously by the Flame malware in 2012. The CMU Software Engineering Institute considers MD5 essentially "cryptographically broken and unsuitable for further use".[4] | ||
easyctf{1_h0p3_y0u_d1dn7_d0_7h47_by_h4nd} | ||
``` | ||
|
||
We learn a few facts about MD5 and get our flag! | ||
|
||
### External Writeups | ||
|
||
* [https://github.com/HackThisCode/CTF-Writeups/tree/master/2017/EasyCTF/Hash%20On%20Hash/README.md](https://github.com/HackThisCode/CTF-Writeups/tree/master/2017/EasyCTF/Hash%20On%20Hash/README.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# Premium RSA - 350 points | ||
|
||
My RSA is the greatest. It's so strong, in fact, that I'll even give you [d](../files/premiumRSA.txt)! | ||
|
||
### Solution | ||
###### Writeup by Valar Dragon | ||
|
||
|
||
|
||
This was a terrific challenge about RSA Partial Key Recovery! (Something I didn't even know existed before) Thankfully we were given over half of the private key. If we were given a quarter of the key, we would have to implement the Coppersmith attack, in addition to whats below. | ||
|
||
**Due to a lack of Latex, if notation is non-standard mathematics notation, it is Python notation** | ||
|
||
We are given N, The last 2048 bits of d, e, and c, and asked to get the message! | ||
|
||
Lets call the least significant 2048 bits of d we have `d0` | ||
|
||
Solving this involved a lot of derivation and reading up on RSA Attacks, namely the following two documents: | ||
* http://www.ijser.org/researchpaper/Attack_on_RSA_Cryptosystem.pdf | ||
* http://honors.cs.umd.edu/reports/lowexprsa.pdf | ||
|
||
The idea is that `ed - k(N-p-q+1) = 1` by definition of modulo. `[1]` | ||
|
||
Note that `N-p-q+1 = φ(N)` | ||
|
||
d must be less than φ(N), since `d = modInv(e,φ(N))` | ||
|
||
Therefore `k < e` since `ed > kφ(N)` | ||
|
||
Thus k is in `range(1,e)`! | ||
|
||
But we don't have φ(N), we have N, so we will switch φ(N) with N in the `[1]` | ||
|
||
Lets call this `d'` since its just an approximation. | ||
`ed' - kN = 1` | ||
|
||
Rearrange, and solve for `d'` as: | ||
|
||
`d' = (kN + 1) // e` | ||
|
||
The maximum error in d' is: `3 sqrt(nBitSize)` bits, where nBitSize is how many bits long the modulus is. See the links for a proof of this maximum error. | ||
|
||
That error is less than `dBitSize/2`, so we can just replace the least significant bits with `d0` | ||
and get the plaintext! | ||
|
||
But we need a way of testing k. One way to do it would be to try encrypting a known message with e and n, and decrypting it with the d were getting from that particular k. | ||
The only issue is that modpows are slow, especially as the exponent d is growing, as is the case with increasing k. | ||
|
||
We actually have a way to speed this up greatly! | ||
Using `[1]` again, | ||
``` | ||
ed - k(N-p-q+1) = 1 | ||
ed ≡ 1 mod k | ||
ed -1 ≡ 0 mod k | ||
``` | ||
Nearly all k will fail that criterion, making it perfect! | ||
I'm then going to decrypt test messages, just to be absolutely sure. | ||
Now we have e,d, and N! Just for completion, lets find p and q. | ||
Rearranging `[1]` | ||
`φ(N) = (ed - 1)//k` | ||
``` | ||
φ(N) = (p-1)(q-1) = n - p - q + 1 | ||
p^2 - p^2 - N + N = 0 | ||
p^2 - p^2 - pq + N = 0 | ||
p^2 + (-p -q)p + N = 0 | ||
p^2 + (φ(N) -n -1) + N = 0 | ||
``` | ||
Solving this quadratic for variable p: | ||
``` python | ||
b = totientN - n - 1 | ||
discriminant = b*b - 4*n | ||
#make sure discriminant is perfect square | ||
root = self.floorSqrt(discriminant) | ||
assert root*root == discriminant | ||
p = (-b + root) // 2 | ||
q = n // p | ||
``` | ||
Now raise the message to d, and we get our flag! | ||
|
||
My code is in [premiumRSA.py](https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Premium%20RSA/premiumRSA.py), the method halfdPartialKeyRecoveryAttack | ||
comes from my RSA Solver, https://github.com/ValarDragon/CTF-Crypto/blob/master/RSA/RSATool.py | ||
|
||
``` bash | ||
$ python3 premiumRSA.py | ||
easyctf{wow_i_pR0bABLY_5h0uldntA_l33k3d_d} | ||
``` | ||
_All the flags have randomized 1337 speak, so your flag may vary_ | ||
### External Writeups | ||
|
||
* [https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Premium%20RSA/README.md](https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Premium%20RSA/README.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Security Through Obscurity - 150 points | ||
|
||
I've never seen such a cryptosystem]before! It looks like a public key cryptosystem, though... Could you help me crack it? | ||
|
||
[encrypt.sage](../files/sage.py) | ||
[publickey_and_ciphertext.txt](../files/key.txt) | ||
|
||
### Solution | ||
###### Writeup by Valar Dragon | ||
|
||
|
||
I think this problem achieves the true definition of failed Security Through Obscurity! These files, except for my [solver](https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Security%20Through%20Obscurity/sageSolver.py), are all sage files. | ||
Sage is an open source python-based alternative to Mathematica and Matlab. | ||
|
||
Lets analyze the code in sage.py | ||
|
||
``` python | ||
def calc_root(num, mod, n): | ||
f = GF(mod) | ||
temp = f(num) | ||
return temp.nth_root(n) | ||
``` | ||
Looking through the Sage documentation, we can see that | ||
f becomes a finite field of order mod. Mod is actually a prime, being passed from `gen_v_list(primelist, p, secret)`. | ||
|
||
temp.nth_root(n) is finding the nth root of temp in this finite field. This means that | ||
``` python | ||
pow(temp.nth_root(n),n) ≡ temp mod num | ||
``` | ||
|
||
This means that we can quite easily brute force for SECRET, see [sageSecret](https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Security%20Through%20Obscurity/sageSecret.py) file. | ||
We don't actually need to solve for SECRET however. | ||
|
||
So now this tells us what | ||
``` python | ||
def gen_v_list(primelist, p, secret): | ||
a = [] | ||
for prime in primelist: | ||
a.append(calc_root(prime, p, secret)) | ||
return a | ||
``` | ||
means. gen_v_list is the nth root of each prime in the finite field of size p. | ||
|
||
``` python | ||
primelist = [2,3,5,7,11,13,17,19,23,29,31,37,43,47,53,59] | ||
message = REDACTED | ||
chunks = [] | ||
for i in range(0,len(message),2): | ||
chunks += [message[i:i+2]] | ||
``` | ||
This splits the message into 2 byte chunks | ||
|
||
``` python | ||
for chunk in chunks: | ||
binarized = bin(int(chunk.encode('hex'),16)).replace('0b','').zfill(16)[::-1] #lsb first | ||
enc = 1 | ||
for bit in range(len(binarized)): | ||
enc *= vlist[bit]**int(binarized[bit]) | ||
enc = enc%p | ||
print(enc) | ||
``` | ||
This converts every chunk to hex, removes any `0b` in the hex, converts it to binary, pads the left with 0's until its 16 bits longs, and then reverses the string. The for loop is multiplying enc by that | ||
index in vlist if binarized[i] is 1. If its 0, then do nothing to enc. Finally take enc modulo p. | ||
|
||
Wait!!! Only 16 bits in a chunk?? That means theres only `2**16 = 65536` options, well within the brute force range! | ||
We can just do a reverse lookup on everything in the ciphertext! | ||
|
||
|
||
Brute forcing all 16 bits of options, and doing reverse lookups on Ciphertext, gives us the flag: | ||
``` bash | ||
$ python3 sageSolver.py | ||
flag{i_actu4lly_d0nt_know_th3_name_of_th15_crypt0sy5tem} | ||
``` | ||
|
||
In discussion with Neptunia, the challenge creator, I found out this was actually an unintended solution, | ||
and this solution reduced the point value from 500 points (iirc), | ||
to this current 150. | ||
|
||
The intended solution involved learning what cryptosystem this is through google, and from there figuring out its decrypt function. | ||
|
||
A link for the cryptosystem given post-CTF on this cryptosystem is: | ||
https://www.di.ens.fr/~stern/data/St63.pdf | ||
### External Writeups | ||
|
||
* [https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Security%20Through%20Obscurity/README.md](https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Security%20Through%20Obscurity/README.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.