0

I am doing a student project to detect attempted logins into windows with wrong passwords (live-time) and warn the user. I detect when the computer is locked, then start listening for event 4648 written to event log.

4648 : A logon attempt with explicit credentials was attempted

My goal is to correctly detect event 4648 when the screen is locked. I have a DateTime.Compare that compares the timestamp when screen is locked and timestamp of 4648 event written. I make sure the handler only triggers if event is written after screen is locked.

What baffles me is how the handler for event 4648 still triggers on correct first-try login attempts.

I have used these posts as reference

Detect windows logon attempts programmatically using C#
c# event handler is called multiple times when event is raised once
Programmatically Determine a Duration of a Locked Workstation?

I have tried unsubscribing from previous event handlers before subscribing again as the post i linked, however to no avail. I can't seem to find the reason why the event handler for 4648 keeps triggering ambiguously.

public static void LoginLogoutDetector()
{
    Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch);
}

//if user locks screen
void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e)
{
    //screen locked detection
    if (e.Reason == SessionSwitchReason.SessionLock)
    {
        EventLog logListener = new EventLog("Security");

        datetime = (DateTime.Now.ToString("dd:MM:yyyy hh:mm:ss tt")).ToString();//get the time of screenlock
        logListener.EntryWritten -= logListener_EntryWritten;//unregister prev subscribers
        logListener.EntryWritten += logListener_EntryWritten;//register 
        logListener.EnableRaisingEvents = true;
    }
    //screen unlock detection
    else if (e.Reason == SessionSwitchReason.SessionUnlock)
    {
        Console.WriteLine("Screen unlocked!");
    }
}//sessionswitch

This is the code for the handler for events written to event log

void logListener_EntryWritten(object sender, EntryWrittenEventArgs e)
{
    //var eventLog = new EventLog("Security", System.Environment.MachineName);
    //eventLog.Clear();
    var events = new long[] { 4648 };

    //only tell me if there is a 4648 event 
    if (events.Contains(e.Entry.InstanceId))
    {
        Console.WriteLine("4648 detected. triggered IF block");
        string eventlogtime = e.Entry.TimeGenerated.ToString();// get timestamp of event log 4648 generated

        //get the timestamp the log was generated (after d2!)
        DateTime d1 = DateTime.Parse(eventlogtime);
        Console.WriteLine("D1 (Event Log Timestamp) " + d1);
        bruteforcelogtime = (d1).ToString();

        //get the timestamp of computer locked (before d1!)
        DateTime d2 = DateTime.ParseExact(datetime, "dd:MM:yyyy hh:mm:ss tt", CultureInfo.InvariantCulture);
        Console.WriteLine("D2 (Computer Locked) :" + d2);

        //d1 = event written
        //d2 = computer locked 
        //event log should always be written after pc lock. d1>d2
        int result = DateTime.Compare(d1, d2);
        Console.WriteLine("Comparing d1,d2 = " + result);
        if (result >= 0)//d1 later than d2
        {
            Console.WriteLine("Login with wrong password was attempted at " + e.Entry.TimeWritten);
            Console.Write("\n");
            MessageBox.Show("bad login detected");
        }
    }
    else
    {
        Console.WriteLine("there were no brute force attempts ( no 4648) ");
    }
}//LoginLogoutDetector

I expect the event handler logListener_EntryWritten to only trigger when there are wrong login attempts. However it triggers even if there is a correct login attempt!

Outputs: even when I login with correct credentials on first try

Screen unlocked!
4648 detected. triggered IF block


D1 (Event Log Timestamp) 2/8/2019 2:44:03 PM
D2 (Computer Locked) :2/8/2019 2:43:59 PM
Comparing d1,d2 = 1
Login with wrong password was attempted at 2/8/2019 2:44:03 PM

there were no brute force attempts ( no 4648) 
there were no brute force attempts ( no 4648) 
there were no brute force attempts ( no 4648) 
there were no brute force attempts ( no 4648) 
there were no brute force attempts ( no 4648) 
CSDev
  • 3,177
  • 6
  • 19
  • 37
  • On a succesfull login it generates a `4624` as well as an `4648`, I haven't checked but I would guess it would generate an additional event when it failed. Maybe you can catch those to determine if it was a failed login attempt or succesfull. – Matthiee Aug 02 '19 at 07:48
  • Thanks for the tip, I did more in-depth digging into `4624` and `4648` as you mentioned, and turns out I found what i was actually looking for was `4625`. Thanks @Matthiee ! – ComprehensiveHydration Aug 02 '19 at 14:41

1 Answers1

0

Turns out I was looking at the wrong event. This is the correct one:
4625 : An Account failed to log on

The solution was to use Logon Auditing , which can be enabled via gpedit.mscBut since I am using Windows 10 Home Edition it doesn't have gpedit.msc installed by default.

I found a workaround via this reddit thread to get gpedit.msc on Win10 home edition
https://www.reddit.com/r/Windows10/comments/adf0xq/you_can_enable_gpeditmsc_in_windows_10_home_by/

From here I followed this guide to enable Logon Auditing
https://www.groovypost.com/howto/check-windows-logon-events-windows-8/

The Event ID to look for is 4625 : An account failed to log on which gets logged once per failed login attempt, thus achieving my desired outcome. I changed 4648 to 4625 in the code, and it works perfectly. Hope this helps others.