Skip to content

Commit 3eaae65

Browse files
committed
Revert "Combine into one file."
This reverts commit b7eee04.
1 parent f452be3 commit 3eaae65

File tree

2 files changed

+369
-364
lines changed

2 files changed

+369
-364
lines changed

cryptography/genius-230-points.md

Lines changed: 0 additions & 364 deletions
Original file line numberDiff line numberDiff line change
@@ -52,370 +52,6 @@ OMG_it_took_like_LITerally_s0oO00_long_2_MAK3_md5_werrk_you_have_no_id34
5252
Putting that into the website's prompt gives a popup with the flag:
5353
`easyctf{OUR_3nCRYpti0n_is_N0T_br0k3n_Ur_brok3n_6c5a390d}`
5454

55-
### Alternate Solution
56-
###### Writeup by rofl0r
57-
Here's the site:
58-
![Screenshot 1](https://raw.githubusercontent.com/ValarDragon/CTF-Writeups/master/2017/EasyCTF/Genius/Site-1.png)
59-
![Screenshot 2](https://raw.githubusercontent.com/ValarDragon/CTF-Writeups/master/2017/EasyCTF/Genius/Site-2.png)
60-
61-
the hash function was available as embedded javascript snippet in the page.
62-
unrolled version:
63-
64-
```js
65-
var super_secret_hash = function(s){
66-
function L(k,d){return(k<<d)|(k>>>(32-d))}
67-
function K(G,k){
68-
var I,d,F,H,x;
69-
F=(G&2147483648);
70-
H=(k&2147483648);
71-
I=(G&1073741824);
72-
d=(k&1073741824);
73-
x=(G&1073741823)+(k&1073741823);
74-
if(I&d){
75-
return(x^2147483648^F^H)
76-
}
77-
if(I|d){
78-
if(x&1073741824){
79-
return(x^3221225472^F^H)
80-
} else {
81-
return(x^1073741824^F^H)
82-
}
83-
} else {
84-
return(x^F^H)
85-
}
86-
}
87-
function r(d,F,k){
88-
return(d&F)|((~d)&k)
89-
}
90-
function q(d,F,k){
91-
return(d&k)|(F&(~k))
92-
}
93-
function p(d,F,k){
94-
return(d^F^k)
95-
}
96-
function n(d,F,k){
97-
return(F^(d|(~k)))
98-
}
99-
function u(G,F,aa,Z,k,H,I){
100-
G=K(G,K(K(r(F,aa,Z),k),I));
101-
return K(L(G,H),F)
102-
}
103-
function f(G,F,aa,Z,k,H,I){
104-
G=K(G,K(K(q(F,aa,Z),k),I));
105-
return K(L(G,H),F)
106-
}
107-
function D(G,F,aa,Z,k,H,I){
108-
G=K(G,K(K(p(F,aa,Z),k),I));
109-
return K(L(G,H),F)
110-
}
111-
function t(G,F,aa,Z,k,H,I){
112-
G=K(G,K(K(n(F,aa,Z),k),I));
113-
return K(L(G,H),F)
114-
}
115-
function e(G){
116-
var Z;
117-
var F=G.length;
118-
var x=F+8;
119-
var k=(x-(x%64))/64;
120-
var I=(k+1)*16;
121-
var aa=Array(I-1);
122-
var d=0;
123-
var H=0;
124-
while(H<F){
125-
Z=(H-(H%4))/4;
126-
d=(H%4)*8;
127-
aa[Z]=(aa[Z]| (G.charCodeAt(H)<<d));
128-
H++
129-
}
130-
Z=(H-(H%4))/4;
131-
d=(H%4)*8;
132-
aa[Z]=aa[Z]|(128<<d);
133-
aa[I-2]=F<<3;
134-
aa[I-1]=F>>>29;
135-
return aa
136-
}
137-
function B(x){
138-
var k="",F="",G,d;
139-
for(d=0;d<=3;d++){
140-
G=(x>>>(d*8))&255;
141-
F="0"+G.toString(16);
142-
k=k+F.substr(F.length-2,2)
143-
}
144-
return k
145-
}
146-
function J(k){
147-
k=k.replace(/rn/g,"n");
148-
var d="";
149-
for(var F=0;F<k.length;F++){
150-
var x=k.charCodeAt(F);
151-
if(x<128){
152-
d+=String.fromCharCode(x)
153-
} else {
154-
if((x>127)&&(x<2048)){
155-
d+=String.fromCharCode((x>>6)|192);
156-
d+=String.fromCharCode((x&63)|128)
157-
} else {
158-
d+=String.fromCharCode((x>>12)|224);
159-
d+=String.fromCharCode(((x>>6)&63)|128);
160-
d+=String.fromCharCode((x&63)|128)
161-
}
162-
}
163-
}
164-
return d
165-
}
166-
var C=Array();
167-
var P,h,E,v,g,Y,X,W,V;
168-
var S=7,Q=12,N=17,M=22;
169-
var A=5,z=9,y=14,w=20;
170-
var o=4,m=11,l=16,j=23;
171-
var U=6,T=10,R=15,O=21;
172-
s=J(s);
173-
C=e(s);
174-
Y=1732584193;
175-
X=4023233417;
176-
W=2562383102;
177-
V=271733878;
178-
for(P=0;P<C.length;P+=16){
179-
h=Y;
180-
E=X;
181-
v=W;
182-
g=V;
183-
Y=u(Y,X,W,V,C[P+0],S,3614090360);
184-
V=u(V,Y,X,W,C[P+1],Q,3905402710);
185-
W=u(W,V,Y,X,C[P+2],N,606105819);
186-
X=u(X,W,V,Y,C[P+3],M,3250441966);
187-
Y=u(Y,X,W,V,C[P+4],S,4118548399);
188-
V=u(V,Y,X,W,C[P+5],Q,1200080426);
189-
W=u(W,V,Y,X,C[P+6],N,2821735955);
190-
X=u(X,W,V,Y,C[P+7],M,4249261313);
191-
Y=u(Y,X,W,V,C[P+8],S,1770035416);
192-
V=u(V,Y,X,W,C[P+9],Q,2336552879);
193-
W=u(W,V,Y,X,C[P+10],N,4294925233);
194-
X=u(X,W,V,Y,C[P+11],M,2304563134);
195-
Y=u(Y,X,W,V,C[P+12],S,1804603682);
196-
V=u(V,Y,X,W,C[P+13],Q,4254626195);
197-
W=u(W,V,Y,X,C[P+14],N,2792965006);
198-
X=u(X,W,V,Y,C[P+15],M,1236535329);
199-
Y=f(Y,X,W,V,C[P+1],A,4129170786);
200-
V=f(V,Y,X,W,C[P+6],z,3225465664);
201-
W=f(W,V,Y,X,C[P+11],y,643717713);
202-
X=f(X,W,V,Y,C[P+0],w,3921069994);
203-
Y=f(Y,X,W,V,C[P+5],A,3593408605);
204-
V=f(V,Y,X,W,C[P+10],z,38016083);
205-
W=f(W,V,Y,X,C[P+15],y,3634488961);
206-
X=f(X,W,V,Y,C[P+4],w,3889429448);
207-
Y=f(Y,X,W,V,C[P+9],A,568446438);
208-
V=f(V,Y,X,W,C[P+14],z,3275163606);
209-
W=f(W,V,Y,X,C[P+3],y,4107603335);
210-
X=f(X,W,V,Y,C[P+8],w,1163531501);
211-
Y=f(Y,X,W,V,C[P+13],A,2850285829);
212-
V=f(V,Y,X,W,C[P+2],z,4243563512);
213-
W=f(W,V,Y,X,C[P+7],y,1735328473);
214-
X=f(X,W,V,Y,C[P+12],w,2368359562);
215-
Y=D(Y,X,W,V,C[P+5],o,4294588738);
216-
V=D(V,Y,X,W,C[P+8],m,2272392833);
217-
W=D(W,V,Y,X,C[P+11],l,1839030562);
218-
X=D(X,W,V,Y,C[P+14],j,4259657740);
219-
Y=D(Y,X,W,V,C[P+1],o,2763975236);
220-
V=D(V,Y,X,W,C[P+4],m,1272893353);
221-
W=D(W,V,Y,X,C[P+7],l,4139469664);
222-
X=D(X,W,V,Y,C[P+10],j,3200236656);
223-
Y=D(Y,X,W,V,C[P+13],o,681279174);
224-
V=D(V,Y,X,W,C[P+0],m,3936430074);
225-
W=D(W,V,Y,X,C[P+3],l,3572445317);
226-
X=D(X,W,V,Y,C[P+6],j,76029189);
227-
Y=D(Y,X,W,V,C[P+9],o,3654602809);
228-
V=D(V,Y,X,W,C[P+12],m,3873151461);
229-
W=D(W,V,Y,X,C[P+15],l,530742520);
230-
X=D(X,W,V,Y,C[P+2],j,3299628645);
231-
Y=t(Y,X,W,V,C[P+0],U,4096336452);
232-
V=t(V,Y,X,W,C[P+7],T,1126891415);
233-
W=t(W,V,Y,X,C[P+14],R,2878612391);
234-
X=t(X,W,V,Y,C[P+5],O,4237533241);
235-
Y=t(Y,X,W,V,C[P+12],U,1700485571);
236-
V=t(V,Y,X,W,C[P+3],T,2399980690);
237-
W=t(W,V,Y,X,C[P+10],R,4293915773);
238-
X=t(X,W,V,Y,C[P+1],O,2240044497);
239-
Y=t(Y,X,W,V,C[P+8],U,1873313359);
240-
V=t(V,Y,X,W,C[P+15],T,4264355552);
241-
W=t(W,V,Y,X,C[P+6],R,2734768916);
242-
X=t(X,W,V,Y,C[P+13],O,1309151649);
243-
Y=t(Y,X,W,V,C[P+4],U,4149444226);
244-
V=t(V,Y,X,W,C[P+11],T,3174756917);
245-
W=t(W,V,Y,X,C[P+2],R,718787259);
246-
X=t(X,W,V,Y,C[P+9],O,3951481745);
247-
Y=K(Y,h);
248-
X=K(X,E);
249-
W=K(W,v);
250-
V=K(V,g)
251-
}
252-
var i=B(Y)+B(X)+B(W)+B(V);
253-
return i.toLowerCase()
254-
}
255-
;
256-
257-
function hash(word) {
258-
var out = "";
259-
for(var i = 0; i < word.length; i += 4) {
260-
out += super_secret_hash(word.substring(i, i + 4));
261-
}
262-
return out;
263-
}
264-
265-
```
266-
what immediately hit my eye is this statement:
267-
```js
268-
for(var i = 0; i < word.length; i += 4) {
269-
out += super_secret_hash(word.substring(i, i + 4));
270-
```
271-
that makes it clear that the final hash is just a concatenation of hashes from the input string in chunks of 4 bytes.
272-
so instead of analyzing the hash function, i just immediately started looking if it is feasible to bruteforce the hash.
273-
274-
for testing, i added the following code to generate a hash from a word passed in as a commandline argument:
275-
```js
276-
word = process.argv[2];
277-
console.log(hash(word));
278-
```
279-
and created the hash of the word "flag".
280-
```
281-
$ node genius-sum.js flag
282-
327a6c4304ad5938eaf0efb6cc3e53dc
283-
```
284-
to generate the candidates for hashing, i used my battle-proofed bruteforce password generator (i call it brutus):
285-
```c
286-
#include <stdio.h>
287-
#include <string.h>
288-
#include <stdlib.h>
289-
290-
struct bruteforcer {
291-
unsigned long long step;
292-
char* out;
293-
size_t out_len;
294-
const char *alpha;
295-
size_t alpha_len;
296-
unsigned *pows;
297-
};
298-
299-
static unsigned long upow(unsigned base, unsigned exp) {
300-
unsigned long res = 1, i=0;
301-
while(i++ < exp) res = res * base;
302-
return res;
303-
}
304-
305-
static unsigned calc_pow(unsigned position, size_t maxlen, size_t alpha_len) {
306-
unsigned r = (maxlen - position) -1;
307-
return upow(alpha_len, r);
308-
}
309-
310-
/* init bruteforcer state. out_len needs to be *not the buffersize*, but the size of characters in out!
311-
that means that you need to put the zero-terminator manually before initialising the state */
312-
static void bruteforcer_init(struct bruteforcer *bf, char* out, size_t out_len, const char* alpha, size_t alpha_len) {
313-
*bf = (struct bruteforcer) {.step = -1ULL, .out = out, .out_len = out_len, .alpha = alpha, .alpha_len = alpha_len};
314-
bf->pows = malloc(sizeof *(bf->pows) * out_len);
315-
unsigned i;
316-
for(i=0; i< out_len; i++) bf->pows[i] = calc_pow(i, out_len, alpha_len);
317-
}
318-
319-
static unsigned powstep(unsigned long long step, unsigned long long pwr, size_t alpha_len, int* termflag) {
320-
unsigned long long d = step / pwr;
321-
if(d < alpha_len) return d;
322-
else *termflag = 1;
323-
return 0;
324-
}
325-
326-
static int bruteforcer_step(struct bruteforcer *b) {
327-
b->step++;
328-
unsigned long long mystep = b->step;
329-
size_t i;
330-
int termflag = 0;
331-
for(i=0;i < b->out_len; i++) {
332-
unsigned pwr = b->pows[i];
333-
unsigned x = powstep(mystep, pwr, b->alpha_len, &termflag);
334-
if(i == 0 && termflag) return 0;
335-
if(x) mystep -= (pwr * x);
336-
b->out[i] = b->alpha[ x ];
337-
}
338-
return 1;
339-
}
340-
341-
static int usage(char *argv0) {
342-
printf(
343-
"brutus 1.0 by rofl0r\n"
344-
"usage: %s alphabet length\n"
345-
"for example:\n"
346-
"%s abcdef 4\n", argv0, argv0);
347-
return 1;
348-
}
349-
350-
int main(int argc, char **argv) {
351-
if(argc != 3) return usage(argv[0]);
352-
const char *alpha = argv[1];
353-
struct bruteforcer b;
354-
int candidatelen = atoi(argv[2]);
355-
char* candidate = malloc(candidatelen+1);
356-
candidate[candidatelen] = 0;
357-
bruteforcer_init(&b, candidate, candidatelen, alpha, strlen(alpha));
358-
while(bruteforcer_step(&b)) puts(candidate);
359-
return 0;
360-
}
361-
```
362-
Then i created a new js file with the hash function and the following snippet:
363-
the idea is to pass the hash as command line argument (`want`), and the candidates to hash and compare via stdin.
364-
```js
365-
want = process.argv[2];
366-
367-
// that's a generic codeblock to be able to read from stdin.
368-
var readline = require('readline');
369-
var rl = readline.createInterface({
370-
input: process.stdin,
371-
output: process.stdout,
372-
terminal: false
373-
});
374-
375-
rl.on('line', function(line){
376-
if (hash(line) === want) {
377-
console.log(line);
378-
process.exit(0);
379-
}
380-
})
381-
```
382-
383-
For the first try i used just a lowercase alphabet against the hash of "flag" to see if the attack is feasible (i.e. fast enough):
384-
385-
```
386-
time ./brutus abcdefghijklmnopqrstuvwxyz 4 | node genius.js 327a6c4304ad5938eaf0efb6cc3e53dc
387-
flag
388-
389-
real 0m1.087s
390-
user 0m1.095s
391-
sys 0m0.008s
392-
```
393-
very promising!
394-
395-
in order to use all 8 available cores, i resorted to my tool [jobflow](https://github.com/rofl0r/jobflow).
396-
it's similar to GNU parallel, but it's much slimmer and faster since it's written in C.
397-
and it uses much less memory. it's also by default installed on my distro [sabotage linux](http://github.com/sabotage-linux/sabotage).
398-
the concept is to evenly distribute the input from brutus to 8 node.js processes running the "password cracker".
399-
i then went to the guts and started cracking the actual hashes of the competition (in 32 byte chunks).
400-
401-
```
402-
time ./brutus _-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 4 | jobflow -j=8 -exec node genius.js 8a7fca9234d2f19c8abfcd812971a26c
403-
OMG_
404-
405-
real 0m24.328s
406-
user 0m1.145s
407-
sys 0m1.535s
408-
409-
```
410-
success! the first part of the input string is `OMG_`.
411-
since the lowercase alphabet didn't cut it, i expanded the alphabet for brutus to include uppercase, lowercase, plus some special chars.
412-
413-
i repeated the process with the other hash chunks, and got the final "password":
414-
`OMG_it_took_like_LITerally_s0oO00_long_2_MAK3_md5_werrk_you_have_no_id34`
415-
416-
Putting that into the website's prompt gives a popup with the flag:
417-
`easyctf{OUR_3nCRYpti0n_is_N0T_br0k3n_Ur_brok3n_6c5a390d}`
418-
41955
### External Writeups
42056

42157
* [https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Genius/README.md](https://github.com/HackThisCode/CTF-Writeups/blob/master/2017/EasyCTF/Genius/README.md)

0 commit comments

Comments
 (0)