⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chntpw.c

📁 The Offline NT Password Editor (c) 1997-2004 Petter Nordahl-Hagen
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * chntpw.c - Offline Password Edit Utility for NT 3.51 4.0 5.0 5.1 SAM database. * 1999-feb: Now able to browse registry hives. (write support to come) * 2000-jan: Attempt to detect and disable syskey * 2000-jun: syskey disable works on NT4. Not properly on NT5. * 2000-jun: changing passwords regardless of syskey. * 2001-jan: patched & changed to use OpenSSL. Thanks to Denis Ducamp * 2001-jul: extra blank password logic (when NT or LANMAN hash missing) * 2002-dec: New option: blank the pass (zero hash lengths). * 2002-dec: New option: Specify user using RID * 2003-jan: Support in ntreg for adding keys etc. Editor updated. * 2003-jan: Changed to use more of struct based V + some small stuff * 2004-jan: Changed some of the verbose/debug stuff * 2004-aug: More stuff in regedit. Stringinput bugfixes. *  * Copyright (c) 1997-2004 Petter Nordahl-Hagen. * Freely distributable in source or binary for noncommercial purposes, * but I allow some exceptions to this. * Please see the COPYING file for more details on * copyrights & credits. *  * Part of some routines, information and ideas taken from * pwdump by Jeremy Allison. * * Some stuff from NTCrack by Jonathan Wilkins. *  *   * THIS SOFTWARE IS PROVIDED BY PETTER NORDAHL-HAGEN `AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <openssl/des.h>#include <openssl/md4.h>#define uchar u_char#define MD4Init MD4_Init#define MD4Update MD4_Update#define MD4Final MD4_Final#include "ntreg.h"#include "sam.h"const char chntpw_version[] = "chntpw version 0.99.3 040818, (c) Petter N Hagen";extern char *val_types[REG_MAX+1];/* Global verbosity */int gverbose = 0;#define MAX_HIVES 10/* Array of loaded hives */struct hive *hive[MAX_HIVES+1];int no_hives = 0;/* Icky icky... globals used to refer to hives, will be * set when loading, so that hives can be loaded in any order */int H_SAM = -1;int H_SYS = -1;int H_SEC = -1;int H_SOF = -1;int syskeyreset = 0;int dirty = 0;int max_sam_lock = 0;/* * of user with RID 500, because silly MS decided * to localize the bloody admin-username!! AAAGHH! */char admuser[129]="Administrator";/* ============================================================== *//* Crypto-stuff & support for what we'll do in the V-value *//* Zero out string for lanman passwd, then uppercase * the supplied password and put it in here */void make_lanmpw(char *p, char *lm, int len){   int i;      for (i=0; i < 15; i++) lm[i] = 0;   for (i=0; i < len; i++) lm[i] = toupper(p[i]);}/* * Convert a 7 byte array into an 8 byte des key with odd parity. */void str_to_key(unsigned char *str,unsigned char *key){	int i;	key[0] = str[0]>>1;	key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);	key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);	key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);	key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);	key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);	key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);	key[7] = str[6]&0x7F;	for (i=0;i<8;i++) {		key[i] = (key[i]<<1);	}	DES_set_odd_parity((des_cblock *)key);}/* * Function to convert the RID to the first decrypt key. */void sid_to_key1(unsigned long sid,unsigned char deskey[8]){	unsigned char s[7];	s[0] = (unsigned char)(sid & 0xFF);	s[1] = (unsigned char)((sid>>8) & 0xFF);	s[2] = (unsigned char)((sid>>16) & 0xFF);	s[3] = (unsigned char)((sid>>24) & 0xFF);	s[4] = s[0];	s[5] = s[1];	s[6] = s[2];	str_to_key(s,deskey);}/* * Function to convert the RID to the second decrypt key. */void sid_to_key2(unsigned long sid,unsigned char deskey[8]){	unsigned char s[7];		s[0] = (unsigned char)((sid>>24) & 0xFF);	s[1] = (unsigned char)(sid & 0xFF);	s[2] = (unsigned char)((sid>>8) & 0xFF);	s[3] = (unsigned char)((sid>>16) & 0xFF);	s[4] = s[0];	s[5] = s[1];	s[6] = s[2];	str_to_key(s,deskey);}/* DES encrypt, for LANMAN */void E1(uchar *k, uchar *d, uchar *out){  des_key_schedule ks;  des_cblock deskey;  str_to_key(k,(uchar *)deskey);#ifdef __FreeBSD__  des_set_key(&deskey,ks);#else /* __FreeBsd__ */  des_set_key((des_cblock *)deskey,ks);#endif /* __FreeBsd__ */  des_ecb_encrypt((des_cblock *)d,(des_cblock *)out, ks, DES_ENCRYPT);}/* Check if hive is SAM, and if it is, extract some * global policy information from it, like lockout counts etc */void check_get_samdata(void){  struct accountdb_F *f;  struct keyval *v;  if (H_SAM >= 0) {    /* Get users F value */    v = get_val2buf(hive[H_SAM], NULL, 0, ACCOUNTDB_F_PATH, REG_BINARY);    if (!v) {      printf("Login counts data not found in SAM\n");      return;    }    printf("\n* SAM policy limits:\n");        f = (struct accountdb_F *)&v->data;    max_sam_lock = f->locklimit;        printf("Failed logins before lockout is: %d\n",max_sam_lock);    printf("Minimum password length        : %d\n",f->minpwlen);    printf("Password history count         : %d\n",f->minpwlen);      }}      /* Try to decode and possibly change account lockout etc * This is \SAM\Domains\Account\Users\<RID>\F * It's size seems to always be 0x50. * Params: RID - user ID, mode - 0 silent, 1 silent, 2 edit. * Returns: ACB bits with high bit set if lockout count is >0 */short handle_F(int rid, int mode){  struct user_F *f;  char s[200];  char yn[10];  struct keyval *v;  unsigned short acb;  int b;  if (H_SAM < 0) return(0);  /* Get users F value */  snprintf(s,180,"\\SAM\\Domains\\Account\\Users\\%08X\\F",rid);  v = get_val2buf(hive[H_SAM], NULL, 0, s, REG_BINARY);  if (!v) {    printf("Cannot find value <%s>\n",s);    return(0);  }  if (v->len != 0x50) {    printf("handle_F: F value is 0x%x bytes, not 0x50, unable to check account flags!\n",v->len);    FREE(v);    return(0);  }  f = (struct user_F *)&v->data;  acb = f->ACB_bits;  if (mode) {    printf("Account bits: 0x%04x =\n",acb);    for (b=0; b < 15; b++) {      printf("[%s] %-15.15s | ",	     (acb & (1<<b)) ? "X" : " ", acb_fields[b] );      if (b%3 == 2) printf("\n");    }    printf("\nFailed login count: %u, while max tries is: %u\n",f->failedcnt,max_sam_lock);    printf("Total  login count: %u\n",f->logins);        if (mode > 1) {      if ( acb & (ACB_DISABLED|ACB_AUTOLOCK) || (f->failedcnt > 0 && f->failedcnt >= max_sam_lock)  ) {	printf("Account is %s\n",(acb & ACB_DISABLED) ? "disabled" : "probably locked out!");	printf("Do you wish me to reset the failed count, unset disabled and lockout,\n");	fmyinput("and set the \"password never expires\" option? (y/n) [n]",yn,2);	if (*yn == 'y') {	  acb |= ACB_PWNOEXP;	  acb &= ~ACB_DISABLED;	  acb &= ~ACB_AUTOLOCK;	  f->ACB_bits = acb;	  f->failedcnt = 0;	  put_buf2val(hive[H_SAM], v, 0, s, REG_BINARY);	  printf("Unlocked!\n");	}      }    }  }  return (acb | ( (f->failedcnt > 0 && f->failedcnt >= max_sam_lock)<<15 ) | (acb & ACB_AUTOLOCK)<<15 | (acb & ACB_DISABLED)<<15);}/* Promote user into administrators group (group ID 0x220) * And remove from all others... * hdesc - hive * rid   - users rid * no returns yet * THIS IS VERY HACKISH YET */void promote_user(int rid){  char s[200];  char g[200];  int nk = 0;  struct keyval *m = NULL, *c = NULL;  struct keyval admember = { 4, 0x220 };  unsigned int *grps, *gcnts;  int count = 0;  int i, size, grp;  if (!rid || (H_SAM < 0)) return;      /* Get member list for user. Go for the first full SID, it's usually local computer I hope */  snprintf(s,180,"\\SAM\\Domains\\Builtin\\Aliases\\Members\\S-1-5-21-\\%08X",rid);  /* Now, the TYPE field is the number of groups the user is member of */  /* Don't we just love the inconsistent use of fields!! */  nk = trav_path(hive[H_SAM], 0, s, 0);  if (!nk) {    printf("Cannot find path <%s>\n",s);    return;  }  nk += 4;  count = get_val_type(hive[H_SAM],nk,"@");  if (count == -1) {    printf("Cannot find value <%s\\@>\n",s);    return;  }  printf("User is member of %d groups.\n",count);    /* This is the data size */  size = get_val_len(hive[H_SAM],nk,"@");    /* It should be 4 bytes for each group */  printf("Data size %d bytes.\n",size);  if (size != count * 4) {    printf("DEBUG: Size is not 4 * count! May not matter anyway. Continuing..\n");  }    m = get_val2buf(hive[H_SAM], NULL, nk, "@", 0);  if (!m) {    printf("Could not get value data! Giving up.\n");    return;  }    printf("User was member of groups: ");  grps = (unsigned int *)&m->data;  for (i = 0; i < count; i++) {    grp = grps[i];    printf("%08x ",grp);    switch (grp) {    case 0x220: printf("=Administrators, "); break;    case 0x221: printf("=Users, "); break;    case 0x222: printf("=Guests, "); break;    default: printf(", "); break;    }    snprintf(g,180,"\\SAM\\Domains\\Builtin\\Aliases\\%08X\\C",grp);    c = get_val2buf(hive[H_SAM], NULL, 0, g, 0);    if (c) {      gcnts = (unsigned int *)&c->data;      gcnts[0xc]--;      /* Decrease members counter */      put_buf2val(hive[H_SAM], c, 0, g, 0);    } else {      printf("Group info for %x not found!\n",grp);    }  }#if 1  printf("\nDeleting user memberships\n");    del_value(hive[H_SAM], nk, "@");    printf("Adding into only administrators:\n");    if (!add_value(hive[H_SAM], nk, "@", 1)) { /* Type is # of groups, here 1 */    printf("Failed to add @ value to key\n");  }#endif  put_buf2val(hive[H_SAM], &admember, nk, "@", 0);    /* Now bumb up administrator groups count */  c = get_val2buf(hive[H_SAM], NULL, 0, "\\SAM\\Domains\\Builtin\\Aliases\\00000220\\C", 0);  if (!c) printf("Group info for 220 (adm) not found!\n");  gcnts = (unsigned int *)&c->data;  gcnts[0xc]++;  put_buf2val(hive[H_SAM], c, 0, "\\SAM\\Domains\\Builtin\\Aliases\\00000220\\C", 0);    printf("Promotion DONE!\n");  }/* Decode the V-struct, and change the password * vofs - offset into SAM buffer, start of V struct * rid - the users RID, required for the DES decrypt stage * * Some of this is ripped & modified from pwdump by Jeremy Allison *  */char *change_pw(char *buf, int rid, int vlen, int stat){      uchar x1[] = {0x4B,0x47,0x53,0x21,0x40,0x23,0x24,0x25};   int pl;   char *vp;   static char username[128],fullname[128];   char comment[128],homedir[128],md4[32],lanman[32];   char newunipw[34], newp[20], despw[20], newlanpw[16], newlandes[20];   char yn[4];   int username_offset,username_len;   int fullname_offset,fullname_len;   int comment_offset,comment_len;   int homedir_offset,homedir_len;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -