CASIMIR
Salut Joe
I found another proprietary crap on my way. This one was just too easy to break in, so i just give a simplified solution, with source code, as usual {;-) Maybe one day i should create my own page, and stop invading yours!!! But it's a good thing to have all the stuff gathered in one location.
I received Randy's book last week, it's great!
The book Caz refers to is the ICSA Guide to Cryptography, by Randy Nichols. In chapter 21, pp. 617-624 Nichols discusses "Reverse Engineering to Snag the Password," which includes part of Casimir's Essay, "CRACKING OF ENCRYPT-IT FOR WINDOWS." --JP
How are you doing with the paper for Bruce?
A while ago, Bruce Schneier asked me to summarize Caz's reversal and cracking of WinXFiles for his "Cryptogram." I summarized it, but I am not sure he will use it -- it is pretty technical...--JP
Looks like Bruce had Mike Stay, a cryptographer at AccessData, write a cryptographic summary of WinXFiles to use in lieu of my somewhat esoteric reversal-assembly essay for Counterpane's February "CRYPTO-GRAM." You should subscribe to it at: Counterpane Systems. It's free and informative. The February issue is primarily on snake oil. --JP
A la prochaine
Caz
YAC by
+++++ +++ + + + +++ + + +++ ++ ++ ++++ + + + + + + + + + +++ + + + +++++++++ + + + +++ + + + + + + + + + + + + + ++++ +++++ + + + + +++ + + + + + + +++ +++ + +defenceless target: Keeper v3.0 by VictoryServices
location: PlanetKeeper
I decided cracking this program after reading their hilarious help file:
Why should I use Keeper?There once was a man at the Zoo that had so many animals he did not know what to do. He would get them them, he would lose them and he would eventually find them. He called his friend the Keeper and ask him what to do.
Keeper said to him, "Let me watch over them and I will tell you what to do". Well, Keeper watched and he thought and he watched and he thought, and after a while he learned what he should do;
"Each type of animal that lives in the Zoo should have its own place - we will make them houses so we know where they are too." he explained to the owner. From that day on, the Zoo owner never had problems with lost or missing animals - and the Keeper was happy that he could be of service.
Like the owner of the Zoo, we have a lot of animals to keep track of - except our animals come in the form of digital information. There are many different digital animals out there - the Password, the Serial Number and the Registration number just to name a few of them. Although they may be digital, they are like the zoo animals - they can not be found when you really need them.
Wouldn't it be great if there was a digital Zoo Keeper to keep track of these digital animals? Well, now there is and it goes by the name of Keeper.
Taken from the Keeper Help file - copyright (c) Geoffrey Steffens.
Well, i would not give a penny for their crypto-software, but i'd really like to know what drug(s) they're using {:-)
Anyway, this app doesn't deserve a fully-documented cracking procedure with tons of asm listing. If for some obscure reason you're interested in such details, e-mail Casimir me, i'll tell you the whole story.
Launch Keeper, enter pwd: CASIMIR. Keeper creates a file called keeper.dat in same directory. Now exit Keeper without storing anything inside, and edit keeper.dat. The 9 first characters are:
8hMAn=LAeThen we have many 00 and 8hMAn=LAe again. Nothing else. We can assume that 8hMAn=LAe is a sort of fingerprint of correct password.
Here is the important stuff:
Keeper uses a table to perform encryption and decryption of both password and data.
Table : 97 ASCII characters, all different
8x3p5Beabcdfghij klmnoqrstuvwyzAC DEFGHIJKLMNOPQRS TUVWXYZ 1246790- //position 56: SPACE .#/\!@$<>&*()[]{ }';:,?=+~`^|%_ //position 95: Carriage Return " //position 96: Line FeedWe start at position 1 with 8 and we end up at position 97 with ": Table[01]=8 Table[97]="
To check if input=pwd, Keeper also uses a check string which is 9 characters long: Check string: ClearText If input equal good pwd, then Check string equal: ClearText If input not equal good pwd, then Check string not equal: ClearText Check string -> C l e a r T e x t Position in Table -> 32 18 07 08 23 49 07 02 25
Suppose you enter 123456 instead of CASIMIR. How can Keeper tell this is not the good pwd?
Fingerprint -> 8 h M A n = L A e Position in Table -> 01 14 42 31 20 87 41 31 07
Input -> 1 2 3 4 5 6 Position in Table -> 57 58 03 59 05 60But Keeper needs 9 characters to perform check. So if Input is < 9 characters, it starts reading it again from the beginning:
Input (extended) -> 1 2 3 4 5 6 1 2 3 Position in Table -> 57 58 03 59 05 60 57 58 03
New position in -> 57-01 58-14 03-42 59-31 05-20 60-87 57-41 58-31 03-07 Table -> 56 44 -39 28 -15 -27 16 27 -04
* position < 0 : position = position + 1 + 97 * position >= 0 : position = position + 1So we obtain:
Position in Table -> 57 45 59 29 83 71 17 28 94
Check string -> 1 P 4 y ; $ k w _ Position in Table -> 57 45 59 29 83 71 17 28 94
1P4y;$kw_ to: ClearText. They differ, so Input is wrong. With Input: CASIMIR we would obtain Check string: ClearText, and Keeper would let us in.
Given a Fingerprint and knowing that Check string is: ClearText, we can easily guess what good input is.
Fingerprint is made of 9 known characters: f1 f2 f3 f4 f5 f6 f7 f8 f9 Input is made of 9 unknown characters: i1 i2 i3 i4 i5 i6 i7 i8 i9 We look for i1,...,i9. Fingerprint -> f1 f2 f3 f4 f5 f6 f7 f8 f9 Position in Table -> pf1 pf2 pf3 pf4 pf5 pf6 pf7 pf8 pf9 Input -> i1 i2 i3 i4 i5 i6 i7 i8 i9 Position in Table -> pi1 pi2 pi3 pi4 pi5 pi6 pi7 pi8 pi9 New position in Table -> pi1-pf1 pi2-pf2 pi3-pf3 pi4-pf4 pi5-pf5 pi6-pf6 pi7-pf7 pi8-pf8 pi9-pf9 To obtain ClearText, we must have: positions = good positions (respectively 32, 18, ... , 25) pi1 - pf1 = 32 -> pi1 = 32 + pf1 pi2 - pf2 = 18 -> pi2 = 18 + pf2 pi3 - pf3 = 07 -> pi3 = 07 + pf3 pi4 - pf4 = 08 -> pi4 = 08 + pf4 pi5 - pf5 = 23 -> pi5 = 23 + pf5 pi6 - pf6 = 49 -> pi6 = 49 + pf6 pi7 - pf7 = 07 -> pi7 = 07 + pf7 pi8 - pf8 = 02 -> pi8 = 02 + pf8 pi9 - pf9 = 25 -> pi9 = 25 + pf9 And we have 2 cases again: * position <= 98 : position = position - 1 * position > 98 : position = position - 1 - 97 For instance, let's recover pwd whose Fingerprint is: 8hMAn=LAe Fingerprint -> 8 h M A n = L A e Position in Table -> 01 14 42 31 20 87 41 31 07 pi1 = 32+pf1 = 32+01 = 33<=98 -> i1 = Table[33-1] = Table[32] = C pi2 = 18+pf2 = 18+14 = 32<=98 -> i2 = Table[32-1] = Table[31] = A pi3 = 07+pf3 = 07+42 = 49<=98 -> i3 = Table[49-1] = Table[48] = S pi4 = 08+pf4 = 08+31 = 39<=98 -> i4 = Table[39-1] = Table[38] = I pi5 = 23+pf5 = 23+20 = 43<=98 -> i5 = Table[43-1] = Table[42] = M pi6 = 49+pf6 = 49+87 = 136>98 -> i6 = Table[136-1-97] = Table[38] = I pi7 = 07+pf7 = 07+41 = 48<=98 -> i7 = Table[48-1] = Table[47] = R pi8 = 02+pf8 = 02+31 = 33<=98 -> i8 = Table[33-1] = Table[32] = C pi9 = 25+pf9 = 25+07 = 32<=98 -> i9 = Table[32-1] = Table[31] = ABecause of wrap, we have 2 pwds possible: CASIMIR and CASIMIRCA. Keeper will stupidly accept both of them, but only one will correctly decrypt data. So if data looks weird, try the other pwd found! (there will never be more than TWO possible pwds)
Obviously, Keeper can't check pwd longer than 9 characters. Anyway, it doesn't matter 'cause Keeper keeps only the first 9 characters from your pwd !!! Yes, the encryption key is only 9 bytes long... quite short!
You probably noticed there is no extended character in Table: in fact Keeper just can't handle extended characters set.
Well, you may understand now why i recommend NOT using this big crap!
And now, TARATATA!!! C source-code for CRKEEPER.EXE -----------------------------------------------------------------------------
#include <stdio.h> #include <io.h> #include <fcntl.h> #include <errno.h> #include <dir.h> #include <string.h> #include <dos.h> #include <alloc.h> #include <malloc.h> #include <stdlib.h> #include <time.h> #include <conio.h> #include <math.h> #define TRUE 1 #define FALSE 0 const int table_size=97; const int check_size=9; //table used by Keeper v3.0 static int Table[table_size]={0x38,0x78,0x33,0x70, 0x35,0x42,0x65,0x61, 0x62,0x63,0x64,0x66, 0x67,0x68,0x69,0x6A, 0x6B,0x6C,0x6D,0x6E, 0x6F,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, 0x79,0x7A,0x41,0x43, 0x44,0x45,0x46,0x47, 0x48,0x49,0x4A,0x4B, 0x4C,0x4D,0x4E,0x4F, 0x50,0x51,0x52,0x53, 0x54,0x55,0x56,0x57, 0x58,0x59,0x5A,0x20, 0x31,0x32,0x34,0x36, 0x37,0x39,0x30,0x2D, 0x2E,0x23,0x2F,0x5C, 0x21,0x40,0x24,0x3C, 0x3E,0x26,0x2A,0x28, 0x29,0x5B,0x5D,0x7B, 0x7D,0x27,0x3B,0x3A, 0x2C,0x3F,0x3D,0x2B, 0x7E,0x60,0x5E,0x7C, 0x25,0x5F,0x0D,0x0A, 0x22}; //check_string used by Keeper v3.0: ClearText static int Good_pos[check_size]={32,18,7,8,23,49,7,2,25}; /****************************** PROTOTYPES *********************************/ void Fill_pattern(int , int ** , int *); void Print_pwd(int , int *); int Multiple(int , int); int Redundant(int , int , int * , int *); void Hi_folks(void); void Calc_finger_pos(int , unsigned char * ,int **); void Calc_pwd_pos(int , int * , int **); void Wait_key(void); void Read_fingerprint(unsigned char ** , int); /********************************* MAIN ************************************/ main() { const int finger_size=9; int pat_size,redund,i; int *Pattern,*Password,*Finger_pos,*Pwd_pos; unsigned char *Fingerprint; Pattern=(int *)malloc(sizeof(int)*finger_size); Fingerprint=(unsigned char *)malloc(sizeof(char)*finger_size); Hi_folks(); //read Fingerprint from file: keeper.dat Read_fingerprint(&Fingerprint,finger_size); //calculate positions in Table for Fingerprint Calc_finger_pos(finger_size,Fingerprint,&Finger_pos); //calculate positions in Table for Password Calc_pwd_pos(finger_size,Finger_pos,&Pwd_pos); //fill Password for(i=0;i<finger_size;i++) { Password[i]=Table[Pwd_pos[i]-1]; } //check if we have a redundand pwd (ex: 123123123) redund=FALSE; for(pat_size=1;pat_size<finger_size;pat_size++) { Fill_pattern(pat_size,&Pattern,Password); if(Redundant(pat_size,finger_size,Pattern,Password)) { redund=TRUE; Print_pwd(pat_size,Pattern); if(!Multiple(pat_size,finger_size)) {Print_pwd(finger_size,Password);} break; } } if(redund==FALSE) {Print_pwd(finger_size,Password);} Wait_key(); exit(0); } /****************************** FUNCTIONS **********************************/ /***************************************************************************/ /* we have: Pwd_pos[i] = Good_pos[i] + Finger_pos[i] */ void Calc_pwd_pos(int finger_size,int *Finger_pos,int **Pwd_pos) { int i,j,pos; for(i=0;i<finger_size;i++) { pos=Good_pos[i]+Finger_pos[i]; if(pos<=(table_size+1)) {(*Pwd_pos)[i]=pos-1;} else {(*Pwd_pos)[i]=pos-table_size-1;} } } /***************************************************************************/ /* find positions in Table for Fingerprint'characters */ /* ex: "a" = 0x61 -> position = 8 */ void Calc_finger_pos(int finger_size,unsigned char *Fingerprint, int **Finger_pos) { int i,j; for(i=0;i<finger_size;i++) { for(j=0;j<table_size;j++) { if(Fingerprint[i]==Table[j]) { (*Finger_pos)[i]=j+1; break; } } } } /***************************************************************************/ /* returns 1 if pattern is redundant (even if only partially), 0 if not */ /* for instance with pattern=ABC: */ /* ABCABCABC -> redundant */ /* ABCABCABCA -> redundant */ /* ABCDABCABC -> not redundant */ int Redundant(int pat_size,int pwd_size,int *Pattern,int *Password) { int i; for(i=pat_size;i<pwd_size;i++) { if(Password[i]!=Pattern[fmod(i,pat_size)]) {return(0);} } return(1); } /***************************************************************************/ /* Read the first pat_size characters from Block and store them in Pattern */ void Fill_pattern(int pat_size,int **Pattern,int *Password) { int i; for(i=0;i<pat_size;i++) {(*Pattern)[i]=Password[i];} } /***************************************************************************/ /* display password along with ASCII values */ void Print_pwd(int pwd_len,int *Pwd) { int i; printf("\n\n ASCII seq: "); for(i=0;i<pwd_len;i++) { printf("[%d]",Pwd[i]); if((i+1)%10==0) {printf("\n ");} } printf("\n\n PASSWORD: >>>"); for(i=0;i<pwd_len;i++) { printf("%c",Pwd[i]); } printf("<<< (%d characters)\n\n",pwd_len); printf("(don't type >>> and <<<)\n"); } /***************************************************************************/ /* return 1 if b = n*a with n integer */ /* return 0 otherwise */ int Multiple(int a,int b) { int remain; remain=fmod(b,a); if(remain==0) {return(1);} return(0); } /***************************************************************************/ void Hi_folks(void) { printf("\n\nYet Another Password Cracker by CASIMIR {;-)"); printf("\n-> Target: Keeper v3.0 by VictoryServices\n"); } /***************************************************************************/ /* Called only once, reads first finger_size characters from keeper.dat */ /* This string is the Fingerprint we rely on to recover password */ void Read_fingerprint(unsigned char **Fingerprint,int finger_size) { int fn; // try to open file keeper.dat fn=open("keeper.dat",O_BINARY|O_RDONLY); switch(fn) { case -1:printf("\nFILE keeper.dat NOT FOUND!"); printf("\nkeeper.dat MUST be in SAME directory as Cracker!\n"); Wait_key(); exit(0); } //(*Buffer)=(unsigned char *)malloc(sizeof(char)*buf_size); // read first check_size characters of file read(fn,*Fingerprint,finger_size); close(fn); } /***************************************************************************/ /* wait for key pressed */ void Wait_key() { printf("\n\n"); printf(" XXXXXXXXXXXXXXXXXXXXXXX\n"); printf(" X hit any key to eXit X\n"); printf(" XXXXXXXXXXXXXXXXXXXXXXX\n"); getch(); {/* wait until key pressed */} //kbhit } If you need more info, contact me at: CasimirHere is Crkeeper, which includes a DOS executable a sample Keeper .DAT file.
Converted to hypertext by Joe Peschel Feb. 14, 1999.