Courtesy of Fravia's page of reverse engineering
Well, this "bozo cracks java" probe reminds me a lot the "triplet" and "ponderated" solution used by Tom in his probe in order to enter the advanced javascript page... one cracker, one solution, many advanced pages?

javascript
Back to Devious javascript

Tom to Fravia+: 26 March 1998




A beautiful one! But we are lucky! No password nor

username were longer than 8 characters and no digits! I

think that the next puzzles will be tougher :-)

After a quick look at the ciphering routines, I gave up

in reversing them: too many floating point problems :(

We can only see that usernames/passwords are not longer

than 10 characters and that targeted page names are

composed of digits.



Let's brute-force:



First try: open all pages with 6 digits names... erhhh

gasp! Forget it ;-)



Second one: I used here the same method than the one I

used to solve the "advanced JavaScript page" puzzle: a

"good English" generator.



Step 1: I've written a little proggy to extract all

letter triplets found in some English texts (downloaded

from a "Project Guttenberg" like site) and stored them

in a "dictionary" file.



Step 2: I grabbed the JavaScript code and converted it

into C++ (straightforward). I kept only the F1() and

F2() functions, etc...

Here's the code:

<hR> // bozo cracks java #include "devious.h" #define PASS_MAX_LEN 8 const char chars[] = { //'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', // 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; // 'e', 's', 'i', 'a', 'r', 'n', 't', 'o', 'l', // 'c', 'd', 'u', 'g', 'p', 'm', 'h', 'b', 'y', 'f', 'v', // 'k', 'w', 'z', 'x', 'j', 'q' }; const __int64 targets[] = { 503200105325677i64, 456044102492218i64, 520110587168960i64, // user 1 478419813816428i64, 500743010138384i64, 493738475696228i64, // user 2 553135480475728i64, 513985012252611i64, 446605401950626i64, // user 3 191979145621879i64, 251426266017281i64, 541311557611052i64, // user 4 498890444152004i64, 500743010138384i64, 417600367517742i64, // user 5 478419813816428i64, 492060879591955i64, 485366930586647i64 }; // user 6 int* triplets = NULL; const int nTriplets = 26*26*26; const int nChars = sizeof(chars)/sizeof(char); const int nTargets = sizeof(targets)/sizeof(__int64); clock_t tm = 0; __int64 count = 0; char buf[PASS_MAX_LEN+1]; __int64 pow1[PASS_MAX_LEN][36], pow2[PASS_MAX_LEN][36]; // precalculated pows int toBase36['a' + 26]; // converts '9' to 9, 'a' to 10 etc... int by26[26*26]; // precalculated products by 26 //* JavaScript Code ******************************************************* // // Encryption operators // You got to alter the following values to get your // own unique encryption code // // 1. The values should be within 0 ... 7 double fi11=2.232, fi12=0.372, fi13=1.322, fi14=5.322, fi15=2.322, fi16=3.771, fi17=2.313, fi18=1.300; double fi21=5.112, fi22=1.472, fi23=4.322, fi24=1.792, fi25=6.737, fi26=2.141, fi27=2.882, fi28=1.382; double fi31=3.342, fi32=5.352, fi33=1.732, fi34=3.008, fi35=1.399, fi36=5.999, fi37=4.913, fi38=2.578; double fi41=3.773, fi42=2.348, fi43=5.769, fi44=2.112, fi45=1.922, fi46=3.573, fi47=3.317, fi48=6.273; double fj11=0.732, fj12=4.732, fj13=4.732, fj14=0.732; double fj21=1.742, fj22=0.102, fj23=1.001, fj24=6.272; double fj31=4.732, fj32=6.212, fj33=6.001, fj34=6.212; double fj41=3.273, fj42=2.723, fj43=1.392, fj44=0.039; double m11=5.7193, m12=5.3732, m13=4.8313, m14=2.3991; double m21=3.3923, m22=3.3021, m23=6.4622, m24=1.1392; double m31=5.3991, m32=2.3010, m33=5.9223, m34=5.8283; double m41=2.3042, m42=1.3923, m43=1.2419, m44=0.3573; // // 2. The following values should be within limits 9.9999 ... 0.0001 // double k11=3.8173, k12=7.2094, k13=0.0001, k14=6.0202, k15=1.9294, k16=0.0011, k17=0.0033, k18=0.0492; double k21=1.3048, k22=0.0083, k23=0.0038, k24=0.0302, k25=2.3935, k26=9.4007, k27=4.2042, k28=0.0004; double k31=0.0298, k32=3.0020, k33=0.0912, k34=0.0123, k35=0.2033, k36=0.0001, k37=3.0034, k38=0.0009; double k41=0.2094, k42=9.0031, k43=5.2059, k44=2.4010, k45=0.0324, k46=0.0023, k47=0.2034, k48=9.9414; // // 3. 'Bases' should be within limits 10...36 (only integer!) // int base1=29, base2=31; // -------------------------------------------- // End of JS code // <hR> // My code starts here // inline int hurts(char* s) { // wait for a three letter string /* if( (s[0] >= '0' && s[0] <= '9') || (s[1] >= '0' && s[1] <= '9') || (s[2] >= '0' && s[2] <= '9') ) return 0; // ignore digits */ return triplets[by26[by26[s[0] - 'a'] + s[1] - 'a'] + s[2] - 'a']; } // the heart of the crack, for each good triplet we store a 1 in // the triplets array at position [26*26*(char 1) + 26*(char 2) + (char 3)] // I used the same technique to generate the input file void getTriplets() { int c, i = 0, idx = 0; while( (c = getchar()) != EOF ) { // skip white spaces if( c == '\n' || c == '\r' || c == ' ' || c == '\t' ) continue; // there are only a-z chars in the generated file if( c < 'a' || c > 'z' ) break; idx *= 26; idx += c - 'a'; if( ++i == 3 ) { triplets[idx] = 1; idx = i = 0; } } } void generate(int n) { static int j, x; static __int64 r1, r2; static __int64 z1 = 0, z2 = 0; static __int64 zz1[PASS_MAX_LEN], zz2[PASS_MAX_LEN]; int i; for( i = 0; i < nChars; i++ ) { x = toBase36[buf[n] = chars[i]]; zz1[n] = z1; zz2[n] = z2; z1 += pow1[n][x]; z2 += pow2[n][x]; if( n < 2 || hurts(&buf[n-2]) != 0 ) { r1 = (__int64)floor(5e14 * sin(m11*sin(z1*k11+fi11) * cos(z1*k12+fi12)+fj11) * sin(m12*sin(z1*k13+fi13) * cos(z1*k14+fi14)+fj12) * sin(m13*sin(z1*k15+fi15) * cos(z1*k16+fi16)+fj13) * sin(m14*sin(z1*k17+fi17) * cos(z1*k18+fi18)+fj14) + 5e14); r2 = (__int64)floor(5e14 * sin(m21*sin(z2*k21+fi21) * cos(z2*k22+fi22)+fj21) * sin(m22*sin(z2*k23+fi23) * cos(z2*k24+fi24)+fj22) * sin(m23*sin(z2*k25+fi25) * cos(z2*k26+fi26)+fj23) * sin(m24*sin(z2*k27+fi27) * cos(z2*k28+fi28)+fj24) + 5e14); count++; for(j = 0; j < nTargets; j += 3) { if( r1 == targets[j] ) { buf[n+1] = 0; printf("%d %c ID : %s\n", j/3+1, ((r1 == targets[j])?' ':'?'), buf); } if( r2 == targets[j+1] ) { buf[n+1] = 0; printf("%d %c PASS: %s\n", j/3+1, ((r2 == targets[j+1])?' ':'?'), buf); } } // next step if( (n+1) < PASS_MAX_LEN ) generate(n+1); } z1 = zz1[n]; z2 = zz2[n]; } } int main(int argc, char** argv) { int i, j; triplets = new int[nTriplets]; memset(triplets, 0, nTriplets * sizeof(int)); getTriplets(); // arrays init // charset to base36 digits for(i = 0; i < 'a' + 26; i++) { if( i >= '0' && i <= '9' ) toBase36[i] = i - '0'; else if( i >= 'a' && i <= 'z' ) toBase36[i] = i - 'a' + 10; else toBase36[i] = 0; } // by 26 products for( i = 0; i < 26 * 26; i++ ) by26[i] = i * 26; // powers precalculation for(i = 0; i < PASS_MAX_LEN; i++) { for( j = 0; j < 36; j++) { pow1[i][j] = (__int64)(pow(base1, i) * j); pow2[i][j] = (__int64)(pow(base2, i) * j); } } memset(buf, 0, sizeof(buf)/sizeof(char)); tm = clock(); generate(0); delete [] triplets; fprintf(stderr, "Computed %I64d possibilities in %.2lfs\n", count, (double)((clock() - tm) / (double)CLOCKS_PER_SEC ) ); return 0; }


Ok, that's not well commented but it should be understandable for all the fellow reverse engineers who reached this page. As you should already have noticed, the dictionary file must be redirected to this program's stdin. I've tested this proggy with different PASS_MAX_LEN values: PASS_MAX_LEN = 4 46,816 possibilities 0.6 s PASS_MAX_LEN = 5 526,561 possibilities 6.6 s PASS_MAX_LEN = 6 5,850,107 possibilities 75.0 s PASS_MAX_LEN = 7 65,730,742 possibilities 14.0 minutes Uh ? where are we going ? PASS_MAX_LEN = 8 736,318,988 possibilities 2 hours 38 minutes I finally got it after 2 hours 38 minutes... I must say that the only missing one was "mozilla" because "moz" didn't figure in my dictionary of 3700 triplets :-( A short estimation tells us that 10 letters usernames and passwords would have required 14 days of computation! Still in "good English". We could include an "error tolerance" check in this code in order to handle digits and other junk like mozilla, but I let you imagine the time required to get in :-D I still don't think that brute forcing was the right solution: does anyone know what happened on 16/05/93 (DD/MM/YY format) ;-) Sincerely yours Tom. Tomflame/usa_net (the real syntax is trivial) // spam@you.net
(c) 1998 Tom All rights reversed

You are deep inside Fravia's page of reverse engineering, choose your way out:

devious
Back to Devious Javascript

redhomepage redlinks redanonymity +ORC redstudents' essays redacademy database
redtools redcocktails redjavascripts wars redantismut CGI-scripts redsearch_forms redmail_Fravia
redIs reverse engineering legal?