colombeen

RunAs GUI with credential manager

9 posts in this topic

#1 ·  Posted (edited)

Hi guys,

 

I was bored and somehow this idea just got stuck in my head to create a RunAs GUI with a credential manager that would run in the system tray which would let you start executable files (exe, msi, ...) by clicking on the tray icon and showing a user defined list of apps that would start directly if only one credential is provided, or would show you a list from which to choose the wanted credentials. the last 2 options from the list would be settings and exit ofcourse.

the settings should bring up a GUI with 2 parts : the credential manager and the application list.

for the applications i would use a FileOpenDialog popup to choose the wanted applications. I would add an optional command line switch(es) field for each app you add. Maybe the option to add apps to categories for better management?

for the credentials i'm not completely sure how I will do it just yet. I was actually hoping to be able to use the windows stored credentials (but i'm not sure if this is possible) as well as adding manual credentials.

Now what is all this about... I was hoping for some input from all you guys on best practices for something like this...
- Would you use (an) ini file(s) to store the applications list and credentials, would you use the registry?
- How do you think the GUI would have to look to be as user friendly as possible?
- Any suggestions on other things to add?
- ...
- Has this already been done and would I be wasting my time?

Let me know and I'll see what I can do (I will post the result on the forum)

 

Greetz

Colombeen

----------------------------------------------

Edit:

This is what I have so far (just testing). The ini files are manually set ATM. Multiple credential support and the management GUI isn't created at this point.

I still have to clean up the code, optimize, add more functions, ... But the first tests seem to work for me.

All files have to be in the same directory at this point.

c-RunAs.au3

#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=icon.ico
#AutoIt3Wrapper_Outfile=c-RunAs.exe
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Comment=RunAs GUI with a credential manager
#AutoIt3Wrapper_Res_Description=RunAs GUI with a credential manager
#AutoIt3Wrapper_Res_Fileversion=1.0.0.0
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=p
#AutoIt3Wrapper_Res_ProductVersion=1.0
#AutoIt3Wrapper_Res_LegalCopyright=Jarno Colombeen
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_requestedExecutionLevel=highestAvailable
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=Y
#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#cs

    Script:         c-RunAs
    Author:         Jarno Colombeen
    Copyright:      colombeen.be

    Description:    RunAs GUI with a credential manager

    Date:           2017/06/16
    AutoIt Version: 3.3.14.2

#ce

#Region General options
Opt("GuiOnEventMode", 1)
Opt("TrayMenuMode", 3)
Opt("TrayOnEventMode", 1)
#EndRegion

#Region General variables
Global $cRunAs_ini_creds = "c-Credentials.ini"
Global $cRunAs_creds
Global $cRunAs_ini_apps = "c-Apps.ini"
Global $cRunAs_apps
Global $cRunAs_cats
; - For the GUI
Global $cRunAs_GUI
Global $cRunAsTitle = "c-RunAs - RunAs GUI with credential manager"
#EndRegion

#Region Required files
#include <Array.au3>
#include <AutoItConstants.au3>
#include <Crypt.au3>
#include <TrayConstants.au3>
#include <WinAPIDiag.au3>
#EndRegion

#Region Init App
_cRunAs()

Func _cRunAs()
    ; Load the credentials if there are any
    If FileExists($cRunAs_ini_creds) Then _cRunAsGetCredentials()
    ; Load the categories and apps
    If FileExists($cRunAs_ini_apps) Then _cRunAsGetApps()
    ; Load the tray app
    _cRunAsTray()
    ; First run ??? Show GUI
    If Not FileExists($cRunAs_ini_apps) Or Not FileExists($cRunAs_ini_creds) Then _cRunAsSettingsGUI()

    While 1
        Sleep(100)
    WEnd
EndFunc ; ==> _cRunAs()
#EndRegion

#Region Helper functions
Func _cRunAsTray()
    ; Show correct icon during development
    If Not @Compiled Then TraySetIcon("icon.ico")

    ; Title
    TrayCreateItem("c-RunAs")
    TrayItemSetOnEvent(-1, "_cRunAsSettingsGUI")
    TrayItemSetState(-1, $TRAY_DEFAULT)

    ; Dynamically create the tray items
    If IsArray($cRunAs_cats) And UBound($cRunAs_cats) > 0 Then
        TrayCreateItem("")
        For $i = 0 To (UBound($cRunAs_cats)-1)
            Local $RunAsMenu = TrayCreateMenu($cRunAs_cats[$i])

            For $j = 0 To (UBound($cRunAs_apps)-1)
                If $cRunAs_cats[$i] = $cRunAs_apps[$j][1] Then
                    TrayCreateItem($cRunAs_apps[$j][0], $RunAsMenu)
                    TrayItemSetOnEvent(-1, "_cRunAsExecute")
                EndIf
            Next
        Next
    EndIf

    ; Create the exit item
    TrayCreateItem("")
    TrayCreateItem("Exit")
    TrayItemSetOnEvent(-1, "_cRunAsExit")

    ; Set tray default
    ;TraySetOnEvent($TRAY_EVENT_PRIMARYDOUBLE, "_cRunAsSettingsGUI")
    TraySetClick(8)
    TraySetState($TRAY_ICONSTATE_SHOW)
    TraySetToolTip("c-RunAs")
EndFunc ; ==> _cRunAsTray()

Func _cRunAsExecute()
    Local $RunAsID = @TRAY_ID
    Local $RunAsName = TrayItemGetText($RunAsID)
    Local $RunAsAppID = _ArraySearch($cRunAs_apps, $RunAsName)
    Local $RunAsUser, $RunAsDomain, $RunAsPassword

    If $RunAsAppID >= 0 Then
        If UBound($cRunAs_creds) = 1 Then
            ; Only one credential found > Run as this user
            $RunAsUser = $cRunAs_creds[0][0]
            $RunAsDomain = $cRunAs_creds[0][1]
            $RunAsPassword = $cRunAs_creds[0][2]
        ElseIf UBound($cRunAs_creds) > 1 Then
            ; Multiple credentials found > Show list to choose from
        Else
            ; There are no credentials > Run as current user
            Run($cRunAs_apps[$RunAsAppID][2] & " " & $cRunAs_apps[$RunAsAppID][3], "")

            If @error Then
                TrayTip("c-RunAs", "Error starting " & $RunAsName & @CRLF & "Error: " & @error & @CRLF & "Extended error: " & @extended, 5)
            Else
                TrayTip("c-RunAs", "Starting " & $RunAsName & @CRLF & "as " & @LogonDomain & "\" & @UserName & @CRLF & "Reason: No other credentials found", 2)
            EndIf

            Return False
        Endif

        RunAs($RunAsUser, $RunAsDomain, $RunAsPassword, 1, $cRunAs_apps[$RunAsAppID][2] & " " & $cRunAs_apps[$RunAsAppID][3], "")

        If @error Then
            Local $error = @error
            Local $extended = @extended
            Local $description = _WinAPI_GetErrorMessage($extended)
            TrayTip("c-RunAs", "Error starting " & $RunAsName & @CRLF & @CRLF & $description & " (Error " & $error & " - " & $extended & ")", 5)
        Else
            TrayTip("c-RunAs", "Starting " & $RunAsName & @CRLF & "as " & $RunAsDomain & "\" & $RunAsUser, 2)
        EndIf
    Else
        MsgBox(16, $cRunAsTitle, "Couldn't find the app information")
    EndIf
EndFunc ; ==> _cRunAsExecute()

Func _cRunAsGetCredentials()
    Local $Credentials = IniReadSectionNames ($cRunAs_ini_creds)

    If Not @error Then
        $cRunAs_creds = 0
        Global $cRunAs_creds[1][3]

        For $i = 1 To $Credentials[0]
            Local $Credential = IniReadSection($cRunAs_ini_creds, $Credentials[$i])

            _ArrayDelete($Credential, 0)
            _ArrayColDelete($Credential, 0)

            _ArrayAdd($cRunAs_creds, $Credential[0][0] & "|" & $Credential[1][0] & "|" & _cRunAsEncryptDecrypt($Credential[2][0], True))
        Next
        _ArrayDelete($cRunAs_creds, 0)
    EndIf
EndFunc ; ==> _cRunAsGetCredentials()

Func _cRunAsGetApps()
    Local $Apps = IniReadSectionNames ($cRunAs_ini_apps)

    If Not @error Then
        $cRunAs_apps = 0
        $cRunAs_cats = 0
        Global $cRunAs_apps[1][4]
        Global $cRunAs_cats[1]

        For $i = 1 To $Apps[0]
            Local $App = IniReadSection($cRunAs_ini_apps, $Apps[$i])

            _ArrayDelete($App, 0)
            _ArrayColDelete($App, 0)

            If _ArraySearch($cRunAs_cats, $App[1][0]) = -1 Then _ArrayAdd($cRunAs_cats, $App[1][0])

            _ArrayAdd($cRunAs_apps, $App[0][0] & "|" & $App[1][0] & "|" & $App[2][0] & "|" & $App[3][0])
        Next

        _ArrayDelete($cRunAs_apps, 0)
        _ArrayDelete($cRunAs_cats, 0)
    EndIf
EndFunc ; ==> _cRunAsGetApps()

Func _cRunAsSettingsGUI()
    ; GUI HERE

    ConsoleWrite(@CRLF & "!> c-RunAs Settings GUI")
EndFunc ; ==> _cRunAsSettingsGUI()

Func _cRunAsExit()
    Exit
EndFunc ; ==> _cRunAsExit()

Func _cRunAsEncryptDecrypt($CryptString, $Decrypt = False)
    Local $CryptAlgorithm = $CALG_AES_256
    Local $CryptKey = "cRunAs" & @ComputerName & "-3nCrÿPt!0n"

    _Crypt_Startup()

    If $Decrypt = False Then
        Return _Crypt_EncryptData($CryptString, $CryptKey, $CryptAlgorithm)
    ElseIf $Decrypt = True Then
        Return BinaryToString(_Crypt_DecryptData($CryptString, $CryptKey, $CryptAlgorithm))
    Endif

    _Crypt_Shutdown()
EndFunc
#EndRegion

c-Apps.ini

[Active Directory]
Name=Active Directory
Category=Administrator
Path="C:\Windows\System32\cmd.exe"
CmdLine=/C START MMC C:\Windows\System32\dsa.msc

[Computer Management]
Name=Computer Management
Category=Administrator
Path="C:\Windows\System32\cmd.exe"
CmdLine=/C START MMC C:\Windows\System32\compmgmt.msc

[DFS Management]
Name=DFS Management
Category=Administrator
Path="C:\Windows\System32\cmd.exe"
CmdLine=/C START MMC C:\Windows\System32\dfsmgmt.msc

[Total Commander]
Name=Total Commander
Category=File managers
Path="C:\Program Files\TotalCommander\TOTALCMD64.EXE"
CmdLine=

c-Credentials.ini

; Replace MyUserName - MyDomain - $CALG_AES_256 encrypted MyPassword with the correct information
[MyUserName]
User=MyUserName
Domain=MyDomain
Password=MyPassword

 

If you have any suggestions, let me know

As it is now, the app uses 3mb memory and as good as nothing for CPU usage.

Edited by colombeen
Updated the script a bit

Share this post


Link to post
Share on other sites



#2 ·  Posted

Hi,

I'm a big fan of portability, so all my programs contain ini files.
I've written an app for my current customer which save s the password in the ini file (encrypted).

Keep in mind, AutoIT can be decompiled, so the seed for encrypting the password can easily be read.
Registry is not my forte, just because then the 'config' file of windows would be even bigger to read at startup.

Have Fun.
 

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Thx for the input Starf0x.

I'm still trying to figure out what would be the best way to use ini files (separate files per category? can I do it all in one file? ... I haven't worked with my own custom ini files so far)

Could you do something like :

[General]
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}

[Scripting]
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}

[Bananas]
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}
{(Here the name),(Here the application path),(Command line switches)}

I've been looking at documentation but it's not really clear on how to add multiple items in one section.

I'm thinking about adding an option to choose if you'd like the creds only to be on the current device (in which case I would add something device specific to the encryption string) or adding them in the application folder

 

EDIT:

Aparently nested sections in ini files aren't really "done" but I found an article that states you should write it like :

[General/Application1]
Name=Application1
Path=ThePathToTheApp
CmdLine=Switches here

[General/Application2]
Name=Application2
Path=ThePathToTheApp
CmdLine=Switches here

...

Does anyone have any experience with this?

Any help would be awesome

Edited by colombeen

Share this post


Link to post
Share on other sites

#4 ·  Posted

Updated my first post

Share this post


Link to post
Share on other sites

#5 ·  Posted

Hi guys, it's been a few days...

I haven't had alot of time... been mostly updating the script with improvements, not so much on the other features.

Removed the categories ini file (I create an array with the categories from the apps ini file)

Instead of constantly reading the ini files I load every ini file into an array at the start

...

I updated the first post with the new code.

thoughts, suggestions, bugs, ... are welcome!

Share this post


Link to post
Share on other sites

#6 ·  Posted

Does anyone have any suggestions for the encryption? Would you encrypt the entire credential ini file or just the passwords?

What encryption algorithm would you use?

Suggestions for the ecryption key?

thx

Share this post


Link to post
Share on other sites

#7 ·  Posted

I encrypted just the passwords & usernames when I used them in an INI.

Use the Crypt.au3 functions.

To help with security since the "seed" is in the file I try not to have a static seed so I use something like @LogonDNSDomain so it runs in the environment I wrote it for, but if somebody magically found my code in the wild they would have no idea what that was.

You can get pretty creative with it, but no solution is perfect.

 

 

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

14 minutes ago, ViciousXUSMC said:

I encrypted just the passwords & usernames when I used them in an INI.

Use the Crypt.au3 functions.

To help with security since the "seed" is in the file I try not to have a static seed so I use something like @LogonDNSDomain so it runs in the environment I wrote it for, but if somebody magically found my code in the wild they would have no idea what that was.

You can get pretty creative with it, but no solution is perfect.

 

 

For testing purposes I'm using this: 

Func _cRunAsEncryptDecrypt($CryptString, $Decrypt = False)
    Local $CryptAlgorithm = $CALG_AES_256
    Local $CryptKey = "cRunAs" & @ComputerName & "-3nCrÿPt!0n"

    _Crypt_Startup()

    If $Decrypt = False Then
        Return _Crypt_EncryptData($CryptString, $CryptKey, $CryptAlgorithm)
    ElseIf $Decrypt = True Then
        Return BinaryToString(_Crypt_DecryptData($CryptString, $CryptKey, $CryptAlgorithm))
    Endif

    _Crypt_Shutdown()
EndFunc

In this case it would differ for each device because I'm using the @computername macro.

I only encrypted the passwords at this point.

What encryption algorithm would you suggest?

Edited by colombeen

Share this post


Link to post
Share on other sites

#9 ·  Posted

Updated my first post.

Added password encryption

Added _WinAPI_GetErrorMessage to show a readable error 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now