aXLe
September 6th, 2005, 21:41
Here is a little Javascript challenge. The source contains the algorithm. Can you reverse it?!
View Full Version : Java script - can you reverse to get password?
<-- Begin
var lpass=(pass.length)+1
for (l=1; l<lpass; l++){
K[l]=pass.charAt(l)
}
var lpass=pass.length
for (l=0; l<lpass; l++){
K[l]=pass.charAt(l)
}
[Originally Posted by aXLe]The trap is that the final password is also the name of the page! The code is implemented as per the code snippet : function go(){ location.href=pass+".html"; ie. with the correct password, you are sent to (password).html. I had culled out this from the pass3.html sample file I uploaded. SO, if there are multiple solutions that generate the correct code, only one will take you to the web page (since the actual password is the name of the page) If the first character is ignored (whether by design or error) that gives another multiple of solutions for the correct password! |
location.href=pass+".html";
[Originally Posted by goggles99]I believe that this js stems originally from the Adobe GoLive JavaScript Library, it's a one-way encryption algorithm. There is tons of info on it already on the internet, To find it, search in google for "(K[y]==base[x])" <- with the quotes ![]() |
[Originally Posted by LLXX]It's hardly "one-way", as demonstrated in the post on the first page of this thread. It is easily invertable. However, in almost all of the results I found searching "(K[y]==base[x])" in Google, its security isn't discussed at all. Perhaps the original author deliberately intended to make this "hash function" contain a lot of collisions, making it more difficult to bruteforce the name of the protected page. |
[Originally Posted by aXLe]Bilbo - thanks! Works great! |
// written by bilbo - 13sep05
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXLEN 50
#define CODE 432195701
char base[10+26+26] = {
'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'
};
int f[10+26+26];
char words[20000][8+1]; // we assume no more than 20000 words will be selected
void
init_f(void)
{
int x, y, z;
char tmp[40];
int tmp1;
for (x=0; x<10; x++) { // digits
f[x] = x << 9;
f[x] += 23;
}
for (x=10,y=28; x<36; x++,y++) { // upper cases
y = y << 1;
_itoa((int)sqrt(y), tmp, 10);
sscanf(tmp, "%x", &tmp1);
f[x] = tmp1 + 5;
}
for (x=36,z=23; x<62; x++,z++) { // lower cases
z = z << 1;
_itoa((int)sqrt(z), tmp, 10);
sscanf(tmp, "%x", &tmp1);
f[x] = tmp1 + 74;
}
}
int
init_dict(void)
{
int i=0;
char buf[50+1];
FILE *fp = fopen("antworth.txt", "r";
if (!fp) {
fprintf(stderr, "Cannot open dict file\n";
exit(0);
}
while (fgets(buf, 50, fp)) if (strlen(buf) == 8+1/*newline*/) {
strncpy(words[I], buf, 8);
words[i++][8] = 0;
}
return i;
}
/*
* used to compare each possible solution against the dictionary words
*/
int __cdecl
cmp(const char *a, const char *b)
{
return stricmp(a, b);
}
void
main(void)
{
unsigned code[MAXLEN]; // leftover at every step
int dictwords, // number of words selected from the dictionary
solutions=0; // possible alphabetic solutions
int i, j, idx;
int last_i[MAXLEN] = {0};
char c;
char buf[8+2]; // possible solution, to be filtered against the dictionary
void *t; // bsearch() result
init_f();
dictwords = init_dict();
printf("Selected %d 8-character words...\n", dictwords);
// first, we find the password length
for (i=2; i<MAXLEN; i++) if (CODE%i == 0) {
printf("found divisor %d => password length may be %d\n", i, i+1);
idx = i;
}
code[idx] = CODE / idx;
printf("\n";
j = idx; // set the initial level to the higher one
while (1) {
if (j != 1) {
for (i=last_i[j]; i<62; i++) if ((code[j]-f[I])%(j-1) == 0) break;
last_i[j] = i+1;
} else { // last level
for (i=last_i[1]; i<62; i++) if (code[1] == (unsigned)f[I]) break;
last_i[j] = i+1;
if (i < 62) // found a complete solution
if (last_i[1]>10 && last_i[2]>10 && last_i[3]>10 &&
last_i[4]>10 && last_i[5]>10 && last_i[6]>10 &&
last_i[7]>10) // only if no numbers are interspersed
// a loop to substitute the first character
for (c='A'; c<='Z'; c++) {
++solutions;
sprintf(buf, "%c%c%c%c%c%c%c%c\n", c,
base[last_i[1]-1], base[last_i[2]-1],
base[last_i[3]-1], base[last_i[4]-1],
base[last_i[5]-1], base[last_i[6]-1],
base[last_i[7]-1]);
t = bsearch(&buf, words, dictwords, 8+1, cmp);
if (t) printf("found solution %s\n", buf);
}
}
// try going one level down
if (i+1<62 && j>1) {
code[j-1] = (code[j]-f[I]) / (j-1);
j--;
} else {
// backstep up, resetting lower levels
if (++j > idx) break; // done
for (i=j-1; i>=0; i--) last_i[I] = 0;
}
}
printf("Alphabetic solutions filtered by dictionary: %d\n", solutions);
}
[Originally Posted by bilbo]You're welcome... But the initial problem is still there: you have to try accessing 20638*62 documents; only one will not return you error 404 (not found) :-) |
[Originally Posted by laola]Well, of course it can be scripted. In perl, you shouldn't need more than a few lines to read line by line from a text file, form an url request and process the web server response. However, whipping out 1.3 million web site requests may qualify you for some inspection from authorities for DOS attempt ![]() |
[Originally Posted by aXLe]One thing I realised though is that since the actual password is the name of a page, which is not case sensitive, then the first character will be in the range 0-9, a-z (can ignore A-Z). 20638*36 is a lot less than 20638*62, but unfortunately is still rather a lot ![]() |
[Originally Posted by aXLe]Oh yeah - one more thing while I think of it. Since the resulting url is a html file that resides in the same folder on the server ( at the root of the web page so to speak) and is not therefore protected by any other security, is there any way to view a list of .html files residing on the server? I'm guessing not. |
[Originally Posted by laola]Could make up for some riddle of notpr0n quality (google for notpr0n if you like creative riddles) |
Characters to constants mapping:
0->23 1->535 2->1047 3->1559 4->2071 5->2583 6->3095 7->3607 8->4119 9->4631 A->12 B->21 C->26 D->38 E->53 F->72 G->101 H->139 I->294 J->375 K->584 L->841 M->1164 N->1678 O->2425 P->4989 Q->6478 R->10076 S->14494 T->21785 U->30621 V->69677 W->87452 X->139356 Y->201113 Z->278810 a->80 b->83 c->93 d->99 e->113 f->131 g->159 h->194 i->346 j->416 k->619 l->861 m->1165 n->1649 o->2256 p->4766 q
->6077 r->9554 s->13713 t->20576 u->28894 v->65661 w->82386 x->131248 y->164801 z->262524
Enter password: goofy
step 1, character 'o': (partialcode 0 + mapping 2256) * 1 = 2256
step 2, character 'o': (partialcode 2256 + mapping 2256) * 2 = 9024
step 3, character 'f': (partialcode 9024 + mapping 131) * 3 = 27465
step 4, character 'y': (partialcode 27465 + mapping 164801) * 4 = 769064
Final code 769064
I am fairly sure that the thought that it is looking for a set number of characters is not true. |
I also dont think it passes over the first character. |
I have tried a 10 letter word that generates a 5 digit number. |
.uNO3
.NuO3
.lUc6
.Ulc6
.bUn6
.Ubn6
.u6cE
.6ucE
.hUOG
.UhOG
.u6bb
.6ubb
.eU5e
.Ue5e
.ucqe
.cuqe
.eU4n
.Ue4n
.rTln
.Trln
.UGkq
.GUkq
.lO5y
.Ol5y
.cO8y
.Oc8y
.NK9y
.KN9y
.D8Ly
.8DLy
.A4Py
.4APy
.oofy
.MJqy
.JMqy
[Originally Posted by Woodmann]Howdy, The script that has been posted here has been altered somewhat. Also, in the original script, the password entered will always return the same generated number. Woodmann |
[Originally Posted by aXLe]I'm pretty sure this actual host is running IIS (returns IIS error about page not found) - does that make it case insensitive as far as the final destination url goes? |