Free YouTube Transcribe

Video transcript

when you change your password, it's already stolen

John Hammond · 3,192 words · 15 min read

WhatsAppTelegramX

Want to search this transcript, jump the video from any line, or download it as TXT, SRT, or VTT?

Open in the transcript tool

Full transcript

0:00What if every time you changed your

0:01password, your new password was

0:04instantly stolen and sent to a hacker?

0:07Turns out on your Windows computer,

0:09that's pretty easy to do because

0:11password filters are a way for

0:14organizations to enforce stricter

0:16password requirements on Windows

0:18accounts than those that are available

0:20by default in the Active Directory Group

0:22Policy. And it's pretty well documented.

0:25This is a write-up and blog post from

0:28Mebix or Rob Fuller titled stealing

0:31passwords every time they change. Now,

0:33granted, this is a very old blog post

0:37and very old write-up and very old

0:39technique, but it still works on modern

0:42Windows. Turns out this password filters

0:45functionality basically lets you run any

0:48code you want whenever any user changes

0:51their password. So, what's to stop you

0:53from listening in in the middle and

0:55capturing that new password? That's

0:57exactly what he did for the National

1:00Collegiate Cyber Defense Competition way

1:02back in 2013.

1:04He created an evil password filter that

1:07basically installed itself and anytime a

1:09password changed, it would store the

1:11password change to a log file in

1:13cleartext as well as issue a little HTTP

1:16post authentication to a server they

1:19own. So, they could exfiltrate the

1:21password and see what those new

1:22sensitive credentials are. But, let's go

1:24take a look at what these password

1:26filters really do based off the

1:28documentation. Now, it's pretty simple.

1:30It provides a way for you to implement a

1:32password policy and change notification.

1:35Whenever a password change request is

1:37made, the Local Security Authority or

1:39LSA calls the password filters

1:42registered on the system. Each password

1:43filter is called twice, interesting.

1:46First to validate the new password and

1:48then after all filters have validated to

1:50notify the filters that a change has

1:51been made. So, basically, we could

1:53register a new notification. If we

1:56listen in on some of the password filter

1:59functions that are defined here in the

2:00security management functions, the

2:03password filter function section, are

2:05the ones that we're most interested in.

2:06The following password filter functions

2:08are implemented by custom password

2:10filter DLLs or dynamic link libraries to

2:14provide password filtering and the

2:16change notification. So, these are the

2:18three functions that we'll need to sort

2:19of wrap around or recreate, right? Add

2:22our own functionality whenever a

2:24password has been changed. And when we

2:27want to put this to use, we go ahead and

2:29install it on the endpoint. Here's the

2:31thing though, this is basically a

2:33backdoor. This is a sort of persistence

2:36mechanism. So, that means you will need

2:39to already be an administrator or have

2:41compromised the machine to the point

2:42where you could set this up. We'll need

2:44to put a DLL or dynamic link library

2:47into C Windows System32, like all the

2:49native and natural Windows binaries are

2:51installed to. And then, we simply update

2:54the registry. But, this is the

2:56HKEY_LOCAL_MACHINE hive, which again

2:58requires administrator privileges. And

3:00then, once you've got this all set up,

3:02you will need to reboot the machine. So,

3:04keep in mind, this is a

3:05post-exploitation technique. Little bit

3:08of persistence, bit of a backdoor, this

3:09is something after you've already gained

3:12admin capability on that host and now

3:14maybe you want to listen and lurk and

3:16capture and collect other credentials

3:18that might be used elsewhere across the

3:19network. And I'm here on the MITRE

3:21ATT&CK framework and you can see some

3:23other hackers or threat actors have done

3:25this in the wild. So, for this video,

3:28let's go ahead and do it. Let's try and

3:30create our own rogue malicious password

3:32filter that could steal passwords every

3:35time they are changed. Now, because we

3:38know we'll need to write a DLL or

3:40dynamic link library, I'm going to open

3:42up Visual Studio so that I could create

3:44a new project and let's look for how we

3:47could make a DLL or dynamic link library

3:49in Windows. I'll click next here and we

3:52could call this like test pass or

3:54whatever, something for us to build out

3:56with the scratchpad. Now, Visual Studio

3:59gives us the boilerplate sort of syntax

4:01and setup for a DLL, but truth be told,

4:04we really don't need that. We're

4:05actually going to sort of get in the

4:07middle of those other Win32 API

4:10functions. We're implementing them as

4:12exports so that our password filter and

4:15now notification provider could respond

4:18to those. Since we're going to be

4:19working with the Windows API, we should

4:21include windows.h,

4:24get the header file, and I think for our

4:26example, we can just write to a log. So,

4:29let's get standard input and output for

4:31a header file as well. Now, let's begin

4:33adding the functions that we need, but

4:35before we do, while we're chatting about

4:37passwords and Active Directory and how

4:39this could very well be used in a domain

4:41controller environment, let me take a

4:43quick second to tell you about the

4:44sponsor of today's video. Let's be

4:46honest, passwords are still a mess.

4:49Forgotten logins, weak credential reuse,

4:52reset tickets clogging up the help desk,

4:54it's a nightmare and attackers know it.

4:57That's why I'm a fan of SpecOps

4:59Software. They take password security

5:02from reactive to proactive. With their

5:04breached password protection, you're

5:06blocking over 4 billion compromised

5:09passwords updated daily from real-world

5:11leaks, [music] live attacks, and even

5:13malware botnets. And it's not just

5:15password resets. SpecOps actively scans

5:18your Active Directory environment and

5:20flags compromised passwords the same day

5:23they show up in the wild. You can even

5:25build custom blocklists so users can't

5:28set passwords with your company name,

5:30project code names, or that one sports

5:32team that everyone's obsessed with in

5:34the office. And for the end users, they

5:36get dynamic feedback that helps them

5:39choose strong passwords that meet policy

5:42without the guessing game. Fewer bad

5:44passwords, fewer help desk tickets.

5:46Throw in self-service password reset and

5:49built-in multi-factor authentication,

5:51and suddenly passwords aren't your

5:53weakest link anymore. They're just one

5:55more thing you've locked down smart.

5:58Check out SpecOps Software and get

6:00started with my link below in the video

6:02description, jh.live/specops.

6:05Huge thanks to SpecOps for sponsoring

6:07this video.

6:09All right, I did forget my using

6:12namespace standard and I think that

6:13might be helpful here, so let's make

6:15sure that's included. And then, let's go

6:17review these password filter functions

6:19that we need to implement in our custom

6:21DLL. First one should be

6:23InitializeChangeNotify

6:25and it looks like that's coming from the

6:26ntsecapi.h

6:29header file, so that might still be

6:30worth including for us because some of

6:32the other maybe parameters or arguments

6:34that will go to other functions would be

6:36worth having. Um, this looks different

6:39in that example than what I was

6:41expecting here, but I don't believe that

6:43takes any arguments. So, let's try to

6:45run with that. And to reference this as

6:47some sort of export, I think we should

6:50be using the extern C declspec thing so

6:54that knows this is an export and we'll

6:58make that a boolean as that's what that

7:00is. But, we do want our

7:02InitializeChangeNotify

7:03function here that takes no arguments.

7:06Void is fine inside the parentheses and

7:09since this is the function that is

7:11called when, okay, it's initialized,

7:13it's not really going to be capturing or

7:15being in the middle of a password. So,

7:18we just need to have this functionality

7:20implemented, like define this function,

7:22but it doesn't need to do anything. So,

7:24we could just like return true even

7:26though it is a boolean, right? That

7:29should make sure it's going to return

7:31some true value. It succeeded, it

7:33worked. Okay. Now, PasswordChangeNotify

7:35is the real thing that we want to get in

7:37the middle of, but before we do, let's

7:39go take a quick look at PasswordFilter

7:41since that validates a new password

7:43based on password policy. Let's go ahead

7:45and look at this. Oh, we should still

7:48import that ntsecapi.h

7:50header. Let me get that included. Now,

7:52this is the password policy portion,

7:55right? This is the functionality in this

7:56callback or this function where you

7:58could test against the password or the

8:01value that's provided to see does it

8:02have however many certain special

8:04characters or whatever. But, again, we

8:07really don't need to get in the middle

8:09of this. We can do that for the latter

8:11function. This being a boolean, we could

8:14just recreate this uh and return true

8:16after the fact. But, we should use a

8:19puny code string as the type in all of

8:21this. Now that this has parameters, it's

8:23worth knowing what these are. So, let me

8:25paste this into our code and let's use

8:27the same sort of setup to declare this

8:30function as we did with the previous.

8:33Uh, we can remove the extra boolean

8:35there and that should just be called

8:37PasswordFilter,

8:38right? And we don't need these in setup.

8:41That's an artifact from copying it from

8:43the documentation, but that's a good way

8:44to know what arguments we would need.

8:47But, remember, this doesn't need to do

8:48anything. We can return true on this one

8:51and then the next function is where the

8:52real magic will happen. So, let's look

8:54at this last one here,

8:55PasswordChangeNotify,

8:57and I think we could, again, just use

9:00this setup and structure for the

9:03function declaration. This is the

9:04notification section and we can see in

9:07the parameters, again, more information

9:09about what username has been set with a

9:11new password. So, let's paste those in

9:14and change these up. This should be a

9:16PasswordChangeNotify

9:18function and that should return an

9:20NTSTATUS

9:22and let's use the same setup here, make

9:26this an export, and I do still want to

9:29use standard call in between that. Okay,

9:31now we need to actually define the

9:33function itself. And if we are just

9:35wanting to write to a file, to log this

9:39for our playground understanding, of

9:41course, you could make this forwarded

9:43out over HTTP or exfiltrate or send the

9:45password and credentials however you

9:47wanted. But, let's just simply start

9:49with a file. Let's try to open that file

9:53and that takes a file stream as like uh

9:56pointer with the ampersand here, so you

9:59get the raw value. We'll need a location

10:01as to where we want to put this on the

10:02file system. We can just call this log

10:04file.text, and let's write it in append

10:07mode. So, if it could not open that

10:11file, if F is equal to null, then we'll

10:14just kind of bail out, return true.

10:18But otherwise, we should write to this

10:20file. So, we could F print F to put data

10:23there using our file handler, and then

10:26what we want to add in. We know we're

10:28going to be working with strings here,

10:30but they are wide strings because it's

10:32Windows world, and we could go ahead and

10:34add in the wide string and another wide

10:38string that follows. And if we're in the

10:39Windows world, I guess backslash R for a

10:42character turn is also worthwhile. And

10:43then, we could just get the username,

10:47since that's included as an argument,

10:48and it is a pointer, P unicode string.

10:51So, let's use the kind of arrow syntax,

10:54rather than using the actual dot syntax

10:57to get a property out of it. Let's use

10:59the buffer value, so we get the real

11:02constant thing there alongside of the

11:05new password. There we go. With that, we

11:08have written, or at least logged and

11:10stolen, whatever password was set. And

11:13let's close our file. Then at the end of

11:15this function, let's be sure to like

11:17return zero. We're good. We're done.

11:19Now, I don't see any errors, and this is

11:22about maybe 37, or like less than 40

11:25lines of C code that was fine. Just

11:28wrapping around the functions that are

11:29necessary to be implemented and exported

11:32for this DLL notification provider with

11:35LSA. So, let's try to compile this. I'm

11:38going to set this in release mode.

11:4064-bit is fine for the computer that I'm

11:42on. So, let me click build solution, and

11:44fingers crossed, we get it to work.

11:46Okay, it's built with testpass.dll.

11:50Uh actually, I did miss something super

11:52important. Uh this string here, where

11:55we're using an absolute file path, using

11:57the backslashes for like a Windows file

12:00path, uh we will need to escape our

12:03backslash, because that's normally

12:04considered an escape character on its

12:06own. To have a literal backslash, we do

12:08need to have two of these here, and

12:10let's make sure to compile and use that

12:13one. So, I'm going to open up a terminal

12:16now, and I will run this as

12:17administrator, right? Let me hit control

12:19shift enter, so I have a UAC prompt, and

12:21because I am backdooring, or applying

12:24this little trick to the machine I'm

12:26using, let me move into the directory

12:28that we had that built in. There it is.

12:31And we know we need to put this into

12:33system32, but we know we're also going

12:35to be making changes to the registry,

12:37and that probably already has some data

12:40there for the regular, normal

12:43notification providers that LSA uses.

12:46So, let's get to HKEY_LOCAL_MACHINE.

12:49Looking back at the documentation to

12:51install and register that, it does need

12:53to be in system, current control set,

12:55control, LSA. System, current control

12:59set, control,

13:02LSA. Okay.

13:04So, take a look. We have a notification

13:07packages key here, or a value set with

13:10the type REG_MULTI_SZ,

13:12with the default value of SCECLI.

13:15So, I could double-click and modify

13:17this, but if that's already a DLL hiding

13:21in C:\Windows\System32,

13:24could we maybe tamper, or get a little

13:27bit clever as to how we hide our new

13:29rogue DLL? Like we know right now, ours

13:32is called testpass.dll,

13:34and if it were like evil password proxy

13:37filter, that would probably, you know,

13:39just be sticking out like a sore thumb.

13:41So, what if we tried to hide this in a

13:42clever way, where we were to copy this

13:46test DLL file into C:\Windows\System32,

13:51but I actually want to call it something

13:52a little bit neat, SCECII.dll,

13:59and you might be able to see it there,

14:01right? Not a lowercase L, but a capital

14:05I, so that in a serif font, excuse me, a

14:09sans font, as you can see our registry

14:11explorer working here, this won't look

14:14all that shady once we've made the

14:16changes here to add in SCEC

14:20capital II.

14:23Looks almost the same as the other one,

14:25but now that is our rogue and malicious

14:28little trick here. This will whine about

14:30some of the empty strings that it found

14:31if you're making this change manually,

14:33but if you double-click, you will still

14:34see this value provided here. So, with

14:37that done, and with that DLL that we've

14:40just created now put into

14:42C:\Windows\System32 in that directory,

14:45let's look for SCECLI.

14:47Take a look.

14:48>> [laughter]

14:49>> Can you tell the difference? Kind of

14:50hard to see. Obviously, the date

14:52modified gives it away, but now our code

14:55should go ahead and log new passwords to

14:57the C drive logfile.text

15:01file that we specified. It doesn't exist

15:03right now, because we haven't rebooted

15:05yet, and the changes haven't been made,

15:07and we haven't tried to change a

15:09password, but let's reboot, and let's

15:11see this in action. Let me go ahead and

15:14restart. Restart anyway. All right, now

15:16let me log in as a separate user. Let's

15:19just log in as John with the password

15:21that he has set for the moment. And now

15:23that I am logged in, we could go explore

15:26in the root of our file system here, the

15:29C drive. Remember our logfile.text that

15:32we're looking for is only told to be

15:34created and written to when we have a

15:37new password being changed. So, let's

15:40try to change our password. While you

15:43could do this with the net user command,

15:45you could do this in some other way.

15:47Obviously, any of the methods that are

15:49really still going to be hooked into, we

15:50can change our password by the GUI, by

15:54whatever method, and let's use a fun one

15:57for our new password. Password hint can

15:59be LOL. Let's click next and finish. And

16:03now, when I go ahead and take a look at

16:05our C drive, we have our log file.

16:08Logfile.text has been created, and you

16:11can see the password that I set. And we

16:13just stole that clear text, plain text

16:16password as it was being changed. Bit of

16:19an odd unicode or some strange character

16:22at the end here, we could see this is

16:23pretty well clear the plain text

16:25password, though. That could have been

16:27anything. And if we look back at the

16:29blog post from Mebix, or Rob Fuller,

16:31again, that was written way back in

16:332013. It says this works from Windows

16:352000, XP, all the way up to Windows 8

16:38and 2012. Granted, I'm testing this on

16:40Windows 11 now in 2025, uh probably

16:43still kicking around. While it's an old

16:45technique, it does work. And let me say,

16:48uh I don't know if I actually drew

16:49attention to this, but like Windows

16:51Defender virus and threat detection is

16:53still on. Uh I could go ahead and go

16:55take a look at all this. Real-time

16:57protection's on, cloud-delivered

16:58protection's on. We can turn on

17:00automatic sample submission if you all

17:01want. Granted, we didn't do anything

17:03malicious. We wrote to a text file,

17:06again using the native and real

17:07functionality of a password filter, but

17:10the registry tweak, all the things that

17:12we did, and that living in system32,

17:15totally A-okay. To your point, though,

17:16you may very well be asking, "Okay,

17:18well, how often are local passwords

17:20changed?" Maybe not often, maybe often

17:23enough, maybe still something that could

17:25glean and glisten some new information

17:27if you're doing some long-term, I don't

17:29know, threat emulation. And when this is

17:31put on a domain controller inside of an

17:33active directory environment, every time

17:36a password is changed by that domain

17:38controller, it's going to be verified by

17:40the password filters. So, if this is

17:42sitting there, listening in, set up as

17:44some post-exploitation, set up as a

17:45little bit of a persistence, or another

17:47trap, you could still be capturing those

17:50credentials. So, there's another trick

17:52for your toolkit, another technique,

17:54maybe old but gold, right? Way back from

17:562013, but still some other trickery you

17:59could do with passwords on Windows.

18:02Stealing a password every time it

18:04changes. And all it takes is just one

18:07file on the file system, and one change

18:09to the registry, and you can get a

18:10little bit sneaky there. So, hey, thanks

18:12so much for watching, everyone. I hope

18:13you enjoyed this video. If you did,

18:15please do all those YouTube algorithm

18:16things, like, comment, subscribe, and

18:18please do give some love to our

18:19sponsors, link below in the video

18:21description. Thanks again. I'll see you

18:23in the next video.

More from John Hammond

All 86 transcripts from John Hammond

Recently added transcripts

Browse the whole transcript library Browse all English transcripts

This transcript was generated from the captions YouTube publishes for this video. Get the transcript of any YouTube video atfreeyoutubetranscribe.com, free, unlimited, no sign-up.