Example #1
0
func main() {
	// Define the flags
	var confPath = flag.String("conf", "", "Configuration file to use")

	// Parse the flags
	flag.Parse()

	// Read the configuration file
	var confFile ini.File
	var confErr error
	if *confPath == "" {
		log.Error("A configuration file was not defined.")
		flag.PrintDefaults()
	}
	confFile, confErr = ini.LoadFile(*confPath)

	// Build the App Controller
	var server AppController

	// Check for errors
	if confErr != nil {
		println("ERROR: Unable to " + confErr.Error())
		println("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
		return
	}

	genConf := confFile.Section("General")

	// Load the CA Certificate, Resource Key, and Resource Certificate from the config
	webRoot, ok := genConf["WebRoot"]
	if !ok {
		log.Error("The WebRoot directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	webRoot = common.StripQuotes(webRoot)

	// Load the CA Certificate, Resource Key, and Resource Certificate from the config
	caCertPath, ok := genConf["CACertFile"]
	if !ok {
		log.Error("The CACertFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	caCertPath = common.StripQuotes(caCertPath)

	// Load the CA Certificate, Resource Key, and Resource Certificate from the config
	caKeyPath, ok := genConf["CAKeyFile"]
	if !ok {
		log.Error("The CAKeyFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	caKeyPath = common.StripQuotes(caKeyPath)

	KeyPath, ok := genConf["KeyFile"]
	if !ok {
		log.Error("The KeyFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	KeyPath = common.StripQuotes(KeyPath)

	CertPath, ok := genConf["CertFile"]
	if !ok {
		log.Error("The KeyFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	CertPath = common.StripQuotes(CertPath)

	// Check for an API SSL/TLS key/cert pair to use
	var useSepAPITLS bool
	APICertPath, APICertOK := genConf["APICertFile"]
	APIKeyPath, APIKeyOK := genConf["APIKeyFile"]
	if APIKeyOK && APICertOK {
		// We found a key and certificate for the API to use so change our boolean marker
		useSepAPITLS = true
	}

	runIP, ok := genConf["BindIP"]
	if !ok {
		runIP = "0.0.0.0"
	} else {
		runIP = common.StripQuotes(runIP)
	}

	runPort, ok := genConf["BindPort"]
	if !ok {
		runPort = "9443"
	} else {
		runPort = common.StripQuotes(runPort)
	}

	switch common.StripQuotes(genConf["LogLevel"]) {
	case "Debug":
		log.SetLevel(log.DebugLevel)
		log.Warn("Please note the debug level logs may contain sensitive information!")
	case "Info":
		log.SetLevel(log.InfoLevel)
	case "Warn":
		log.SetLevel(log.WarnLevel)
	case "Error":
		log.SetLevel(log.ErrorLevel)
	case "Fatal":
		log.SetLevel(log.FatalLevel)
	case "Panic":
		log.SetLevel(log.PanicLevel)
	default:
		log.SetLevel(log.InfoLevel)
	}

	lf := common.StripQuotes(genConf["LogFile"])
	if lf != "" {
		hook, err := cracklog.NewFileHook(lf)
		if err != nil {
			println("ERROR: Unable to open log file: " + err.Error())
		} else {
			log.AddHook(hook)
		}
	}

	var statefile string
	statefile = common.StripQuotes(genConf["StateFile"])

	var updatetime int
	var resourcetimeout int
	utconf := common.StripQuotes(genConf["UpdateTime"])
	if utconf != "" {
		var err error
		updatetime, err = strconv.Atoi(utconf)
		if err != nil {
			log.WithField("error", err.Error()).Error("Unable to parse update time in config file.")
			updatetime = 30
		}
	} else {
		updatetime = 30
	}
	restimeconf := common.StripQuotes(genConf["ResourceTimeout"])
	if restimeconf != "" {
		var err error
		resourcetimeout, err = strconv.Atoi(restimeconf)
		if err != nil {
			log.WithField("error", err.Error()).Error("Unable to parse resource timeout in config file.")
			resourcetimeout = 5
		}
	} else {
		resourcetimeout = 5
	}

	log.WithFields(log.Fields{
		"ip":   runIP,
		"port": runPort,
	}).Info("Starting queue server up.")

	// Get the Authentication configuration
	confAuth := confFile.Section("Authentication")
	if confAuth == nil {
		println("Error: Authentication configuration is required.")
		println("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
		return
	}

	_, weberr := os.Stat(webRoot)
	if weberr != nil {
		println("Error: Public web root '" + webRoot + "' does not exist.")
		return
	}

	// Check for type of authentication and set conf
	switch confAuth["type"] {
	case "INI":
		var i INIAuth

		// Get the users
		umap := map[string]string{}

		au := common.StripQuotes(confAuth["adminuser"])
		if au == "" {
			log.Fatal("An administrative user was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}
		ap := common.StripQuotes(confAuth["adminpass"])
		if ap == "" {
			log.Fatal("An administrative password was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}

		su := common.StripQuotes(confAuth["standarduser"])
		if su == "" {
			log.Fatal("An standard user was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}
		sp := common.StripQuotes(confAuth["standarduser"])
		if sp == "" {
			log.Fatal("An standard password was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}

		ru := common.StripQuotes(confAuth["readonlyuser"])
		if ru == "" {
			log.Fatal("An read only user was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}
		rp := common.StripQuotes(confAuth["readonlypass"])
		if rp == "" {
			log.Fatal("An read only password was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}

		umap[au] = ap
		umap[su] = sp
		umap[ru] = rp

		// Setup group mappings
		gmap := map[string]string{}

		gmap[au] = Administrator
		gmap[su] = StandardUser
		gmap[ru] = ReadOnly

		i.Setup(umap, gmap)

		server.Auth = &i

		log.Info("INI authentication setup complete.")
	case "ActiveDirectory":
		var ad ADAuth

		realm := common.StripQuotes(confAuth["realm"])
		if realm == "" {
			log.Fatal("No Active Directory realm was configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}
		ad.SetRealm(realm)

		gmap := map[string]string{}
		ro := common.StripQuotes(confAuth["ReadOnlyGroup"])
		if ro == "" {
			log.Fatal("A read only group was not provided. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}
		st := common.StripQuotes(confAuth["StandardGroup"])
		if st == "" {
			log.Fatal("A group for standard access was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}
		admin := common.StripQuotes(confAuth["AdminGroup"])
		if admin == "" {
			log.Fatal("A group for read only access was not configured. See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files#queue-auth")
		}

		gmap[ReadOnly] = ro
		gmap[StandardUser] = st
		gmap[Administrator] = admin

		ad.Setup(gmap)

		server.Auth = &ad
		log.WithFields(log.Fields{
			"readonly": ro,
			"standard": st,
			"admin":    admin,
		}).Info("Active directory authentication configured successfully.")
	}

	// Configure the TokenStore
	server.T = NewTokenStore()

	// Configure the Queue
	server.Q = queue.NewQueue(statefile, updatetime, resourcetimeout)

	caBytes, err := ioutil.ReadFile(caCertPath)
	if err != nil {
		println("ERROR: " + err.Error())
	}

	caPool := x509.NewCertPool()
	caPool.AppendCertsFromPEM(caBytes)

	tlscert, err := tls.LoadX509KeyPair(CertPath, KeyPath)
	if err != nil {
		log.Fatalf("Failed to load cert pair for Q and R connecton. %s\n", err.Error())
	}

	// Setup TLS connection for the Queue and Resource communication
	qandrTLSConfig := &tls.Config{}
	qandrTLSConfig.Certificates = make([]tls.Certificate, 1)
	qandrTLSConfig.Certificates[0] = tlscert
	qandrTLSConfig.RootCAs = caPool
	qandrTLSConfig.ClientCAs = caPool
	qandrTLSConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
	qandrTLSConfig.MinVersion = tls.VersionTLS12
	qandrTLSConfig.SessionTicketsDisabled = true

	// Check if we are using a different TLS configuration for the API portion of the Queue
	if useSepAPITLS {
		apiCert, err := tls.LoadX509KeyPair(APICertPath, APIKeyPath)
		if err != nil {
			log.Fatalf("API Cert and Key set, but could not be loaded. %s\n", err.Error())
		}
		apiTLSConfig := &tls.Config{
			Certificates: []tls.Certificate{apiCert},
			CipherSuites: []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA,
				tls.TLS_RSA_WITH_AES_256_CBC_SHA,
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
				tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
			MinVersion:             tls.VersionTLS12,
			SessionTicketsDisabled: true,
		}

		server.TLS = apiTLSConfig
	} else {
		// No separate API key was set so use the same we did for the internal communication
		server.TLS = qandrTLSConfig
	}

	// Add some nice security stuff
	secureMiddleware := secure.New(secure.Options{
		SSLRedirect:             true,
		FrameDeny:               true,
		CustomFrameOptionsValue: "SAMEORIGIN",
		BrowserXssFilter:        true,
		IsDevelopment:           true,
	})

	// SETUP RESOURCE MANAGERS
	// Get the Authentication configuration
	confResMgr := confFile.Section("ResourceManagers")
	if confResMgr == nil {
		println("Error: Resource manager configuration is required.")
		println("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
		return
	}

	// First, let's setup the direct connect manager if we have anything there
	if _, ok := confResMgr["directconnect"]; ok {
		resmgr_dc := directconnectresourcemanager.Setup(&server.Q, qandrTLSConfig)
		server.Q.AddResourceManager(resmgr_dc)
	}

	// Now let's setup the AWS manager if we have a config file
	if resDC, ok := confResMgr["aws"]; ok {
		resmgr_aws, err := awsresourcemanager.Setup(resDC, &server.Q, qandrTLSConfig, caCertPath, caKeyPath)
		if err != nil {
			log.WithField("error", err.Error()).Error("Unable to setup AWS resource manager.")
		} else {
			server.Q.AddResourceManager(resmgr_aws)
		}
	}

	// Build the Negroni handler
	n := negroni.New(negroni.NewRecovery(),
		cracklog.NewNegroniLogger(),
		negroni.NewStatic(http.Dir(webRoot)))

	n.Use(negroni.HandlerFunc(secureMiddleware.HandlerFuncWithNext))
	n.UseHandler(server.Router())
	log.Debug("Negroni handler started.")

	listen, err := tls.Listen("tcp", runIP+":"+runPort, server.TLS)
	if err != nil {
		println("ERROR: Unable to bind to '" + runIP + ":" + runPort + "':" + err.Error())
		return
	}

	err = http.Serve(listen, n)
	if err != nil {
		log.Fatal("Unable to start up web server: " + err.Error())
	}
}
Example #2
0
func main() {
	//Set our logger to STDERR and level
	log.SetOutput(os.Stderr)

	// Define the flags
	var confPath = flag.String("conf", "", "Configuration file to use")

	// Parse the flags
	flag.Parse()

	// Read the configuration file
	var confFile ini.File
	var confError error
	if *confPath == "" {
		log.Error("A configuration file was not included on the command line.")
		flag.PrintDefaults()
		return
	}
	confFile, confError = ini.LoadFile(*confPath)

	if confError != nil {
		log.Error("Unable to load configuration file:" + confError.Error())
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
		return
	}

	//  Check for auth token
	resConf := confFile.Section("General")
	if len(resConf) == 0 {
		// We do not have configuration data to quit
		log.Error("There was a problem parsing the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
		return
	}

	// Load the CA Certificate, Resource Key, and Resource Certificate from the config
	caCertPath, ok := resConf["CACertFile"]
	if !ok {
		log.Error("The CACertFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	caCertPath = common.StripQuotes(caCertPath)

	resKeyPath, ok := resConf["KeyFile"]
	if !ok {
		log.Error("The KeyFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	resKeyPath = common.StripQuotes(resKeyPath)

	resCertPath, ok := resConf["CertFile"]
	if !ok {
		log.Error("The KeyFile directive was not included in the 'General' section of the configuration file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
	}
	resCertPath = common.StripQuotes(resCertPath)

	runIP, ok := resConf["BindIP"]
	if !ok {
		runIP = "0.0.0.0"
	} else {
		runIP = common.StripQuotes(runIP)
	}

	runPort, ok := resConf["BindPort"]
	if !ok {
		runPort = "9443"
	} else {
		runPort = common.StripQuotes(runPort)
	}

	switch common.StripQuotes(resConf["LogLevel"]) {
	case "Debug":
		log.SetLevel(log.DebugLevel)
	case "Info":
		log.SetLevel(log.InfoLevel)
	case "Warn":
		log.SetLevel(log.WarnLevel)
	case "Error":
		log.SetLevel(log.ErrorLevel)
	case "Fatal":
		log.SetLevel(log.FatalLevel)
	case "Panic":
		log.SetLevel(log.PanicLevel)
	default:
		log.SetLevel(log.InfoLevel)
	}

	lf := common.StripQuotes(resConf["LogFile"])
	if lf != "" {
		hook, err := cracklog.NewFileHook(lf)
		if err != nil {
			log.Error("Unable to open log file: " + err.Error())
		} else {
			log.AddHook(hook)
		}
	}

	log.WithFields(log.Fields{
		"conf": *confPath,
		"ip":   runIP,
		"port": runPort,
	}).Debug("Config file setup")

	// Create a resource queue
	resQueue := resource.NewResourceQueue()

	//Get the configuration section for plugins
	pluginConf := confFile.Section("Plugins")
	if len(pluginConf) == 0 {
		log.Error("No plugin section in the resource server config file.")
		log.Error("See https://github.com/jmmcatee/cracklord/src/wiki/Configuration-Files.")
		return
	}
	if common.StripQuotes(pluginConf["hashcat"]) != "" {
		hashcat.Setup(common.StripQuotes(pluginConf["hashcat"]))
		resQueue.AddTool(hashcat.NewTooler())
	}
	if common.StripQuotes(pluginConf["nmap"]) != "" {
		nmap.Setup(common.StripQuotes(pluginConf["nmap"]))
		resQueue.AddTool(nmap.NewTooler())
	}
	if common.StripQuotes(pluginConf["johndict"]) != "" {
		johndict.Setup(common.StripQuotes(pluginConf["johndict"]))
		resQueue.AddTool(johndict.NewTooler())
	}
	if common.StripQuotes(pluginConf["testtimer"]) == "true" {
		testtimergpu.Setup()
		testtimercpu.Setup()
		resQueue.AddTool(testtimergpu.NewTooler())
		resQueue.AddTool(testtimercpu.NewTooler())
	}

	// Get an RPC server
	res := rpc.NewServer()

	// Register the RPC endpoints
	res.Register(&resQueue)

	caBytes, err := ioutil.ReadFile(caCertPath)
	if err != nil {
		log.Error("Unable to read CA certificate: " + err.Error())
		return
	}

	// Load the CA file
	caPool := x509.NewCertPool()
	caPool.AppendCertsFromPEM(caBytes)

	// Load the cert and key files
	tlscert, err := tls.LoadX509KeyPair(resCertPath, resKeyPath)
	if err != nil {
		log.Error("There was an error loading the resource key or certificate files: " + err.Error())
		return
	}

	// Setup TLS connection
	tlsconfig := &tls.Config{}
	tlsconfig.Certificates = make([]tls.Certificate, 1)
	tlsconfig.Certificates[0] = tlscert
	tlsconfig.RootCAs = caPool
	tlsconfig.ClientCAs = caPool
	tlsconfig.ClientAuth = tls.RequireAndVerifyClientCert
	tlsconfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
		tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
	tlsconfig.MinVersion = tls.VersionTLS12
	tlsconfig.SessionTicketsDisabled = true

	listen, err := tls.Listen("tcp", runIP+":"+runPort, tlsconfig)
	if err != nil {
		log.Error("Unable to bind to '" + runIP + ":" + runPort + "':" + err.Error())
		return
	}

	log.WithFields(log.Fields{
		"ip":   runIP,
		"port": runPort,
	}).Info("Listening for queueserver connection.")

	// Accept only one connection at a time
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Error("Failed to accept connection: " + err.Error())
			return
		}

		res.ServeConn(conn)
	}

	log.Info("Connection closed, stopping resource server.")

	listen.Close()
}