Courtesy of reverser'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?
Back to Devious javascript
Tom to reverser+: 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:
// 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
//
// 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 reverser's page of reverse engineering,
choose your way out:
Back to Devious Javascript
homepage
links
anonymity
+ORC
students' essays
academy database
tools
cocktails
javascripts wars
antismut CGI-scripts
search_forms
mail_reverser
Is reverse engineering legal?