Courtesy of Fravia's page
of reverse engineering
Well, some simple steps for newbyes, a nice C++ probe (which deserves
your attention) and some Zen considerations... nice reading, isn't it?
"?vemuffrer" sounds to me like an old piece of sliced bread long forgotten in some
drawer "You should'nt eat that vemuffrer thing, Gretchen!"... I wonder how comes it
got such an high ponderation :-)
Back to Advanced javascript
Tom to Fravia+: 26 March 1998
How dummy I was! That's it! Listen to me fellow newbies
(Yes, I haven't got much experience in cracking)! Zen,
Zen, and much more Zen! In this case, semantics is the
key. Don't act like me, hoping that the solution will
come to you after just "some" Zen, you need a lot more
to get it :-) Perhaps, later will it come quicker
(that's called "experience" ;-).
Let's study the "Easy entrance to the advanced
JavaScript page" step by step:
Step 1: Turn off JavaScript in your browser, grab the
JavaScript code and modify it to dump the values of
f[].
Step 2: Determine the possible password lengths: with
the biggest value of f[] we obtain 7 characters (the
result is still less than the final code), and with the
smallest value of f[] we obtain 13 characters. The
length of the significant part of the password is in
range [8;13].
Since the final code can only be divided by 9 in the
[8;13] range, the password length is 10 (including the
first character ignored by the check routine).
Note also that the first two characters can be
switched.
Step 3: Some brute forcing with a short proggy (se the
other essays) shows quickly that there are too many
possibilities to try them all. What we need here is
lots of Zen.
Step 4: Switch off your computer and eat your windoze CD
(Yes, it helps :o), and... Zen!
Step 5: Given that the password is the name of the html
page, we can hopefully get rid of uppercase letters,
coz their use on a web server often leads to a "Object
not found" message in your browser (depending from the
"comprehension" between your browser and the host
operating system). Anyway we must reduce the number of
possibilities, so go on and calculate how many there are
now:
The short proggy tells us: 5767 (without the first
random character :-). Still too huge!
Step 6: It's the end of the brute force method. If we
can't find another way to reduce the number of
possibilities, we're stuck here. If Fravia+ said that we
can break it, it must be something "easy". After a
little exam we can see that the last letters must be in
{h, i, r, w}: the filename doesn't end with a digit...
Did he dare to put a(some) digit(s) right in the middle
of a filename? Could it be something like "java2advan"?
May be. We can't discard numbers for now. If the
filename isn't somehow meaningful, trying the hard
entrance would be quite the same (just have a look at
it ;o). Once more: Zen!
Step 7: Semantics. The targeted page is about java, so
it's name contains certainly "ja" or "jav" or "java".
After having filtered all passwords containing any of
these subsets (don't forget to consider the first
character in your pattern matching!), it gives 112
remaining possibilities And that's only for the
significant part. There is a total of 62 x 112 = 6944
possible passwords... Perhaps a subset of "Fravia"? It
will certainly lead to the same conclusion: still too
much possibilities. Anyway, the password could be
"bozo2trash". Bad weather! Never mind, let's try the
"good english" filtering.
The program makes some statistics about all "good
english" letter triplets found in each password
computed. Each good triplet found increases the current
score by one. If the final score is (or will be ;-)
less than the minimal score passed on the command line,
the password is rejected. In our case, consider that
the max possible score is 7 (9 minus 2) and that a
single disturbing character (like a digit) in the
middle of the password will reduce the score to 4. When
I experimented, the good password popped up with a
minimal score of 5 (calculation time is about 7 seconds
on a P233):
5 ?varnrdich (Deutsch ?)
...
5 ?vemuikich
...
5 ?vnlawkich
5 ?v9nabouch
5 ?9vnabouch
5 ?8veiswuch
5 ?vadusna6r
...
5 ?varhovidr
...
6 ?vdcurther
5 ?dvcurther
advcurther (may be...)
5 ?vafurther
avafurther (this one ?)
...
5 ?avfurther
...
favfurther (or this one ?)
...
javfurther (oh !)
lavfurther
navfurther (??)
...
5 ?verilvher (Deutsch ?)
...
5 ?nvinwdjer (some other Nordic language ?)
...
7 ?vemuffrer Hi-score ! But... what does it mean ???
...
5 ?evmuffrer
...
5 ?kvaullrer
5 ?v4osiorer
5 ?4vosiorer
6 ?ulwaporer (junk, junk, and more junk)
...
6 ?vbdurtrer
5 ?bvdurtrer
obvdurtrer
5 ?kfxtutrer
...
5 ?fkxtutrer
* 24 passwords with a min score equal to 5
Note that I wrote before a little word parser that
stored in a file all letter triplets found in some
english texts (downloaded from a "Project Guttenberg"
like site). The generated file is redirected to the
password cracker's stdin (I obtained a dictionary
containing about 3700 triplets).
Here's the C++ (C should work too, needs __int64
support) source code of my password cracker. Don't
blame me for the poor comments nor for the junky style:
I hadn't much time to write this proggy and you are
all reverse engineers, aren't you ? ;-)
#include
#include
#include
#define BOZO_MAX_CHARS 9
const char base[] = { '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',
'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' };
const long f[] = { 23, 535, 1047, 1559, 2071, 2583, 3095, 3607, 4119, 4631,
// 12, 21, 26, 38, 53, 72, 101, 139, 294, 375, 584, 841, 1164,
// 1678, 2425, 4989, 6478, 10076, 14494, 21785, 30621, 69677, 87452, 139356, 201113, 278810,
80, 83, 93, 99, 113, 131, 159, 194, 346, 416, 619, 861, 1165,
1649, 2256, 4766, 6077, 9554, 13713, 20576, 28894, 65661, 82386, 131248, 164801, 262524 };
int* triplets;
__int64 nTarget = 25834242042i64;
__int64 nSols = 0;
const int nKeys = sizeof(f)/sizeof(long);
const int nTriplets = 26*26*26;
char buf[BOZO_MAX_CHARS + 2];
char tbuf[BOZO_MAX_CHARS + 2];
int nMinScore = 0;
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;
return triplets[((((s[0] - 'a') * 26) + s[1] - 'a') * 26) + s[2] - 'a'];
}
// the recursive one, the leasy way
void test(__int64 code, int n, int score)
{
int i;
if( n == 0 )
{
if( code == "0.class" tppabs="http://Fravia.org/0.class" && score >= nMinScore )
{
int j;
buf[0] = '?';
printf("%d %s\n", score, buf);
for(j = 0; j < 26; j++)
{
if( tbuf[1] >= 'a' && tbuf[1] <= 'z' && tbuf[2] >= 'a' && tbuf[2] <= 'z'
&& triplets[(((j * 26) + tbuf[1] - 'a') * 26) + tbuf[2] - 'a'] == 1 )
{
buf[0] = j + 'a';
printf(" %s\n", buf);
}
}
nSols++;
}
else if( code == "0.class" tppabs="http://Fravia.org/0.class" )
fprintf(stderr, "%s\r", buf); // progress indicator
return;
}
// time killer 1000%
if( n + score < nMinScore )
return;
if( (code % n) == 0 )
{
code /= n;
for(i = 0; i < nKeys; i++)
{
buf[n] = base[i];
tbuf[n] = (buf[n] >= 'A' && buf[n] <= 'Z') ? buf[n] + 32 : buf[n];
test(code-f[i], n-1, score + ((n < 8)?hurts(&tbuf[n]):0));
}
}
return;
}
// 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;
}
}
}
// type | passit
int main(int argc, char** argv)
{
__int64 code = 0;
if( argc > 1 )
nMinScore = atoi(argv[1]);
if( nMinScore < 0 ) nMinScore = 0;
tbuf[0] = buf[0] = '?';
tbuf[BOZO_MAX_CHARS+1] = buf[BOZO_MAX_CHARS+1] = '\0';
triplets = new int[nTriplets]; // C users: use malloc() instead
memset(triplets, 0, nTriplets * sizeof(int));
getTriplets();
test(nTarget, BOZO_MAX_CHARS, 0);
fprintf(stderr, "* %I64d passwords with a min score equal to %d\n", nSols, nMinScore);
delete [] triplets; // C users: use free() instead
return 0;
}
That's all folks !
(c) 1998 Tom All rights reversed
You are deep inside Fravia's page of reverse engineering,
choose your way out:
Back to Advanced Javascript
homepage
links
anonymity
+ORC
students' essays
academy database
tools
cocktails
javascripts wars
antismut CGI-scripts
search_forms
mail_Fravia
Is reverse engineering legal?