Example #1
0
// SimpleHashcatRules applies the basic hashcat rules based on delete, insert, replace
func SimpleHashcatRules(word []rune, password []rune, operations []EditOp) []string {
	if string(word) == string(password) {
		return []string{":"}
	}

	temp := make([]rune, len(word))
	copy(temp, word)
	r := []string{}

	for _, op := range operations {
		if op.Op == "insert" {
			r = append(r, fmt.Sprintf("i%d%c", op.P, password[op.P]))
			temp = rules.InsertAtN(temp, op.P, password[op.P])
		} else if op.Op == "delete" {
			r = append(r, fmt.Sprintf("D%d", op.P))
			temp = rules.DeleteN(temp, op.P)
		} else if op.Op == "replace" {
			r = append(r, fmt.Sprintf("o%d%c", op.P, password[op.P]))
			temp = rules.OverwriteAtN(temp, op.P, password[op.P])
		}
	}

	if string(temp) == string(password) {
		return r
	}

	return nil
}
Example #2
0
// RuleWorks tests if a rule results in the correct managled word
func RuleWorks(word []rune, password []rune, operations []EditOp) bool {
	temp := make([]rune, len(word))
	copy(temp, word)

	for _, op := range operations {
		if op.Op == "insert" {
			rules.InsertAtN(temp, op.P, password[op.P])
		} else if op.Op == "delete" {
			rules.DeleteN(temp, op.P)
		} else if op.Op == "replace" {
			rules.OverwriteAtN(temp, op.P, password[op.P])
		}
	}

	if string(temp) == string(password) {
		return true
	}

	return false
}
Example #3
0
// AdvancedHashcatRules applies all hashcat rules to a word
func AdvancedHashcatRules(passwordString, wordString string, perations []EditOp) []string {

	// TODO
	// can we do this earlier not in this function to save a fucntion call
	if passwordString == wordString {
		return []string{":"}
	}

	password := []rune(passwordString)
	word := []rune(wordString)

	needNewName := []string{}
	// this holds the current mangled as rules are applied
	wordRules := make([]rune, 0, len(word))
	wordRules = append(wordRules, []rune(word)[:]...)

	var passwordLower int
	var passwordUpper int
	for _, r := range password {
		if unicode.IsLower(r) {
			passwordLower++
		} else if unicode.IsUpper(r) {
			passwordUpper++
		}
	}

	for i, op := range perations {

		if op.Op == "insert" {
			needNewName = append(needNewName, fmt.Sprintf("i%c%c", rules.ToAlpha(op.P), password[op.P]))
			wordRules = rules.InsertAtN(wordRules, op.P, password[op.P])
		} else if op.Op == "delete" {
			needNewName = append(needNewName, fmt.Sprintf("D%c", rules.ToAlpha(op.P)))
			wordRules = rules.DeleteN(wordRules, op.P)
		} else if op.Op == "replace" {

			// rule was made obsolete by prior global replacement
			// test to see if word is greater than password to avoid index error
			if len(wordRules) >= len(password) && wordRules[op.P] == password[op.P] {
				if *debug {
					fmt.Println("obsolete rule")
				}

				// Swapping rules
			} else if op.P < len(password)-1 && op.P < len(word)-1 &&
				word[op.P] == password[op.P+1] &&
				word[op.P+1] == password[op.P] {

				if op.P == 0 && RuleWorks(word, password, perations[i+1:]) {
					needNewName = append(needNewName, "k")
					wordRules = rules.SwapFront(wordRules)
				} else if op.P == len(wordRules)-2 && RuleWorks(rules.SwapBack(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "K")
					wordRules = rules.SwapBack(wordRules)
				} else if RuleWorks(rules.SwapAtN(wordRules, op.P, op.P+1), password, perations[i+1:]) {
					// Swap any two characters (only adjacent swapping is supported)
					needNewName = append(needNewName, fmt.Sprintf("*%c%c", op.P, rules.ToAlpha(op.P+1)))
					wordRules = rules.SwapAtN(wordRules, op.P, op.P+1)
				} else {
					needNewName = append(needNewName, fmt.Sprintf("o%c%c", rules.ToAlpha(op.P), password[op.P]))
					wordRules = rules.OverwriteAtN(wordRules, op.P, password[op.P])
				}

				// Case Toggle: Uppercased a letter
			} else if unicode.IsLower(wordRules[op.P]) && unicode.ToUpper(wordRules[op.P]) == password[op.P] {
				// Toggle the case of all characters in word (mixed cases)
				if passwordUpper > 0 && passwordLower > 0 && RuleWorks(rules.ToggleCase(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "t")
					wordRules = rules.ToggleCase(wordRules)
					// Capitalize all letters
				} else if RuleWorks(rules.Uppercase(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "u")
					wordRules = rules.Uppercase(wordRules)
					// Capitalize the first letter
				} else if op.P == 0 && RuleWorks(rules.Capitalize(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "c")
					wordRules = rules.Capitalize(wordRules)
					// Toggle the case of characters at position N
				} else {
					needNewName = append(needNewName, fmt.Sprintf("T%c", rules.ToAlpha(op.P)))
					wordRules = rules.ToggleAt(wordRules, op.P)
				}

				// Case Toggle Lowercased a letter
			} else if unicode.IsUpper(wordRules[op.P]) && unicode.ToLower(wordRules[op.P]) == password[op.P] {
				// Toggle the case of all characters in word (mixed cases)
				if passwordUpper > 0 && passwordLower > 0 && RuleWorks(rules.ToggleCase(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "t")
					wordRules = rules.ToggleCase(wordRules)
					// Lowercase all letters
				} else if RuleWorks(rules.Lowercase(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "l")
					wordRules = rules.Lowercase(wordRules)
					// Lowercase the first found character, uppercase the rest
				} else if op.P == 0 && RuleWorks(rules.InvertCapitalize(wordRules), password, perations[i+1:]) {
					needNewName = append(needNewName, "C")
					wordRules = rules.InvertCapitalize(wordRules)
					// Toggle the case of characters at position N
				} else {
					needNewName = append(needNewName, fmt.Sprintf("T%c", rules.ToAlpha(op.P)))
					wordRules = rules.ToggleAt(wordRules, op.P)
				}

				// Special case substitution of 'all' instances (1337 $p34k)
			} else if unicode.IsLetter(wordRules[op.P]) && !unicode.IsLetter(password[op.P]) &&
				RuleWorks(rules.Replace(wordRules[0:], wordRules[op.P], password[op.P]), password, perations[i+1:]) {

				needNewName = append(needNewName, fmt.Sprintf("s%c%c", wordRules[op.P], password[op.P]))
				wordRules = rules.Replace(wordRules, wordRules[op.P], password[op.P])

				// Replace next character with current
			} else if op.P < len(password)-1 && op.P < len(wordRules)-1 &&
				password[op.P] == password[op.P+1] && password[op.P] == wordRules[op.P+1] {
				needNewName = append(needNewName, fmt.Sprintf(".%c", rules.ToAlpha(op.P)))
				wordRules = rules.ReplaceNPlus(wordRules, op.P)

				// Replace previous character with current
			} else if op.P > 0 && op.Word > 0 && password[op.P] == password[op.P-1] && password[op.P] == wordRules[op.P-1] {
				needNewName = append(needNewName, fmt.Sprintf(",%c", rules.ToAlpha(op.P)))
				wordRules = rules.ReplaceNMinus(wordRules, op.P)

				// ASCII increment
			} else if wordRules[op.P]+1 == password[op.P] {
				needNewName = append(needNewName, fmt.Sprintf("+%c", rules.ToAlpha(op.P)))
				wordRules = rules.ASCIIIncrementPlus(wordRules, op.P)

				// ASCII decrement
			} else if wordRules[op.P]-1 == password[op.P] {
				needNewName = append(needNewName, fmt.Sprintf("-%c", rules.ToAlpha(op.P)))
				wordRules = rules.ASCIIIncrementMinus(wordRules, op.P)

				// SHIFT left
			} else if wordRules[op.P]<<1 == password[op.P] {
				needNewName = append(needNewName, fmt.Sprintf("L%c", rules.ToAlpha(op.P)))
				wordRules = rules.BitwiseShiftLeft(wordRules, op.P)

				// SHIFT right
			} else if wordRules[op.P]>>1 == password[op.P] {
				needNewName = append(needNewName, fmt.Sprintf("R%c", rules.ToAlpha(op.P)))
				wordRules = rules.BitwiseShiftRight(wordRules, op.P)

				// Position based replacements.
			} else {
				needNewName = append(needNewName, fmt.Sprintf("o%c%c", rules.ToAlpha(op.P), password[op.P]))
				wordRules = rules.OverwriteAtN(wordRules, op.P, password[op.P])
			}

		}
	}
	// out of for loop

	// these next things convert rules to append $ and prepend rules

	// TODO
	// possibility to have either what the rule is now or
	// the rule swapped with these replacements

	// Prefix rules
	lastPrefix := 0
	var prefixRules []string
	for i, hashcatRule := range needNewName {
		if hashcatRule[0] == 'i' && rules.ToNumByte(hashcatRule[1]) == lastPrefix {
			prefixRules = append(prefixRules, fmt.Sprintf("^%c", hashcatRule[2]))
			lastPrefix++
			needNewName[i] = fmt.Sprintf("^%c", hashcatRule[2])
		} else {
			// TODO
			// dont know about breaking early here
			break
		}
	}

	// Appendix rules
	lastAppendix := len(password) - 1
	var appendixRules []string
	for i, hashcatRule := range needNewName {
		if hashcatRule[0] == 'i' && rules.ToNumByte(hashcatRule[1]) == lastAppendix {
			appendixRules = append(appendixRules, fmt.Sprintf("$%c", hashcatRule[2]))
			lastAppendix--
			needNewName[i] = fmt.Sprintf("$%c", hashcatRule[2])
		} else {
			break
		}
	}

	// Truncate left rules
	lastPrecut := 0
	for i, hashcatRule := range needNewName {
		if hashcatRule[0] == 'D' && rules.ToNumByte(hashcatRule[1]) == lastPrecut {
			needNewName[i] = "["
		} else {
			break
		}
	}

	// Truncate right rules
	lastPostcut := len(password)
	for i, hashcatRule := range needNewName {
		if hashcatRule[0] == 'D' && rules.ToNumByte(hashcatRule[1]) >= lastPostcut {
			needNewName[i] = "]"
		} else {
			break
		}
	}

	/*
		// naive implementation of OMN
		// will only work if the first rule is a delete
		overwrite := 0
		for i, hashcatRule := range needNewName {
			if hashcatRule[0] == 'D' && i < len(password)-1 && needNewName[i+1] == 'D' {
				overwrite++
				needNewName[i] = ""
			} else {
				break
			}
		}
		if overwrite > 0 {
			var temp []string
			temp = append(temp, fmt.Sprintf("O%c%c", rules.ToAlpha(0), rules.ToAlpha(overwrite)))
			temp = append(temp, needNewName[:]...)
			needNewName = temp
		}
	*/

	// Check if rules result in the correct password
	if string(wordRules) == passwordString {
		return needNewName
	}

	log.Printf("advanced processing failed: P: %s, M: %s, O: %s, %v\n", passwordString, string(wordRules), wordString, needNewName)
	return nil
}