打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
AD DS部署、日志采集、自动化脚本
userphoto

2022.06.08 江苏

关注
一. AD DS简介
Active Directory域服务 (AD DS) 可存储有关网络上的用户、计算机和其他资源的信息。AD DS 可帮助管理员安全地管理此信息。还便于在用户中实现共享和协作。AD DS 是启用了目录的应用程序(如 Microsoft Exchange Server)和其他 Windows Server 技术(如组策略)所必需的。
AD域登录认证过程
二. 服务器
1.DC服务器
主机名主机IP角色系统
ad1.test.com192.168.10.10master1WindowsServer2019
ad2.test.com192.168.10.11master2WindowsServer2019
AD DS服务安装
两台DC安装Winlogbeat
2.ELK服务器
请使用三台及以上的es来搭建群集,我这里只是实现了主从而并没有实现高可用
主机名主机IP角色系统
ELK192.168.20.10master1CentOS7.5.1804
ELK2192.168.20.11node1CentOS7.5.1804
三. 组织架构
四. 配置常规组策略
1. 自动锁屏
组策略管理编辑器 => 用户配置 => 策略 => 管理模板 => 控制面板 => 个性化
启用屏幕保护程序 配置为已启用
阻止更改屏幕保护程序 配置为已启用
带密码的屏幕保护程序 配置为已启用
屏幕保护程序超时 配置为已启用 秒:300
2.账号密码设置
组策略管理器编辑器 => 计算机配置 => 策略 => Windows 设置 => 安全设置 => 账户策略 => 密码策略
密码必须符合复杂性要求:已启用
密码长度最小值:8个字符
密码最短使用期限:0
密码最长使用期限:0
强制密码历史:没有定义
3.账户锁定
组策略管理器编辑器 => 计算机配置 => 策略 => Windows 设置 => 安全设置 => 账户策略 => 账户锁定策略
账户锁定时间 设置为0,需管理员手动解锁
账户锁定阀值 设置为8,用户连续输入错误8次则该用户被锁定
重置账户锁定计数器 设置为30分钟之后,表示在8次内输入的次数计数器在30分钟后重置为0
4.登录时间限制
用户属性 => 账户 => 登录时间
5.用户登录指定主机(修改密码后自动绑定)
用户属性 => 账户 => 登录到 => 下列计算机
6.USB禁用
组策略管理编辑器 => 用户配置 => 策略 => 管理模板 => 系统 => 可移动存储访问
可移动磁盘:拒绝读取权限 配置已启动
7.桌面设置
组策略管理编辑器 => 用户配置 => 策略 => 管理模板 => 桌面 => 桌面
桌面墙纸 创建共享,将设置的用户或组添加到照片上
注:组策略设置用户桌面配置后,用户无法再手动设置桌面
8.下发证书
计算机配置 => 策略 => Windows设置 => 安全设置 => 公钥策略 => 受信任的根证书颁发机构 => 导入只读共享目录下的证书
9.msi软件下发
组策略管理编辑器 => 用户配置 => 策略 => 软件设置 => 软件安装
新建数据包 => 选择共享目录下的msi文件 => 部署类型为“ 已分配” => 部署选项“在登录时安装此应用程序”
10.AD用户本地管理员权限
组策略管理编辑器 => 用户配置 => 首选项 => 控制面板设置 => 本地用户和组 => 新建本地组
操作:更新
组名:Administrators
添加当前用户、删除所有成员用户、删除所有成员组
添加Domain Adminis 组
五. DC安全
AD DS 服务涉及到的固定端口,同时其中组策略和RPC会使用动态TCP和UDP端口,为了保证服务的可靠性,我们使用防火墙默认开通的AD DS服务的相关规则,关闭其他非相关服务,同时入站对389端口、445端口、3389端口等做IP地址的限制。
固定TCP端口:389,636,3268,3269,88,53,445,445,25,135,5722,464,138,9369,139
固定UDP端口:389,88,53,445,123,464,138,137
1. 开启AD DC防火墙
2. 关闭其他非相关服务规则,关键端口IP限制
135、389、445、636、3389端口对指定网段或IP放通
六. Windows安全事件日志收集
1. DC开启身份验证服务组策略
通常用户每次在登录域主机时,都会向DC的DS进行身份认证并由TGS颁发服务请求票据(TGT),根据事件的event.code和winlog.event_data.Status可以筛选出用户登录成功和失败以及非法登录。
参考Windows Security Log Events,这里需要用到的域主机登录事件:
登录情况分类winlog.event_data.Statusevent.code
非AD用户名登录0x64768
AD用户名登录,密码错误0x184771
AD用户名登录,密码正确0x04768
一个帐户无法登录4625
尝试使用显式凭据登录4648
用户帐户已被锁定4740
试图更改帐户密码4723
组策略管理编辑器 => 计算机配置 => 策略 => Windows 设置 => 安全设置 => 高级审查策略配置 => 审核策略 => 账户登录 => 审核Kerberos 身份验证服务 => 勾选 “成功” 和“失败”
组策略管理编辑器 => 计算机配置 => 策略 => Windows 设置 => 安全设置 => 高级审查策略配置 => 审核策略 => 账户管理=> 审核用户账户管理 => 勾选 “成功” 和“失败”
组策略管理编辑器 => 计算机配置 => 策略 => Windows 设置 => 安全设置 => 高级审查策略配置 => 审核策略 => 登录/注销 => 审核登录 => 勾选 “成功” 和“失败”
打开CMD窗口输入 gpupdate /force 强制刷新组策略
使用域用户账号登录已加入域的主机,在AD DC上查看 事件查看器 => Windows 日志 => 安全
2. 安装Winlogbeat + Logstash + Elasticsearch + Kibana
官网下载 Winlogbeat解压包和其他RPM安装
配置Winlogbeat客户端
将Winlogbeat 收集的日志以负载均衡的方式发送到Logstash
output.logstash: # The Logstash hosts hosts: ["192.168.20.11:5044","192.168.20.10:5044"] loadbalance: true
.\winlogbeat.exe run 或 安装启动winlogbeat服务
配置logstash,以192.168.20.10为例
[root@ELK ~]# vim /etc/logstash/conf.d/windowsServerAD_events.conf
input { beats { port => 5044 }}# Active Directory Kerberos pre-authentication failed # Add field user_ip to store ip of hostfilter { if [winlog][channel] == "Security" and [winlog][event_id] == 4771 and [winlog][event_data][IpAddress] == "::1" { mutate { add_field => {"user_ip" => "%{[host][ip]}"} } }}# Active Directory A Kerberos authentication ticket (TGT) was requested# Add field user_ip to store ip of hostfilter { if [winlog][channel] == "Security" and [winlog][event_id] == 4768 and [winlog][event_data][IpAddress] == "::1" { mutate { add_field => {"user_ip" => "%{[host][ip]}"} } }}# Filter ip of client filter { if "ffff" in [winlog][event_data][IpAddress] { grok { match => {"[winlog][event_data][IpAddress]" => "%{IPV4:user_ip}"} } }}# Output to elasticsearchoutput { if [winlog][channel] == "Security" and ([winlog][event_id] == 4771 or [winlog][event_id] == 4723 ) and "192.168.10" not in [user_ip] { elasticsearch { hosts => ["http://192.168.20.10:9200"] index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" #user => "elastic" #password => "changeme" } } # Get useful events else if [winlog][channel] == "Security" and [winlog][event_id] == 4768 and "$" not in [winlog][event_data][TargetUserName] and "TEST" in [winlog][event_data][TargetDomainName]{ elasticsearch { hosts => ["http://192.168.20.10:9200"] index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" #user => "elastic" #password => "changeme" } } else if [winlog][channel] == "Security" and [winlog][event_id] == 4625 and "$" not in [winlog][event_data][TargetUserName] { elasticsearch { hosts => ["http://192.168.20.10:9200"] index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" #user => "elastic" #password => "changeme" } } else if [winlog][channel] == "Security" and [winlog][event_id] == 4740 and "$" not in [winlog][event_data][TargetUserName] { elasticsearch { hosts => ["http://192.168.20.10:9200"] index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" #user => "elastic" #password => "changeme" } } else if [winlog][channel] == "Security" and [winlog][event_id] == 4648 and "$" not in [winlog][event_data][TargetUserName] { elasticsearch { hosts => ["http://192.168.20.10:9200"] index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" #user => "elastic" #password => "changeme" } }}
配置 Elasticsearch,以192.168.20.10为例
[root@ELK ~]# vim /etc/elasticsearch/elasticsearch.ymlcluster.name: elk-clusternode.name: ELKnetwork.host: 192.168.20.10discovery.seed_hosts: ["192.168.20.10", "192.168.20.11"]cluster.initial_master_nodes: ["192.168.20.10","192.168.20.11"]
配置Kibana ,以192.168.20.10为例
[root@ELK ~]# vim /etc/kibana/kibana.ymlserver.host: "192.168.20.10"i18n.locale: "zh-CN"
启动服务
[root@ELK ~]# systemctl start logstash elasticsearch kibana
3. 配置 kibana dashboard
kibana筛选并可视化数据
1.0 当日域用户登录域主机失败记录winlog.event_data.Status:0x18 event.code:4771 1.1 当日域用户登录域主机失败时序图winlog.event_data.Status.keyword : "0x6" or (event.code: 4771 and winlog.event_data.Status.keyword : "0x18")---------------------------------------------2.0 当日错误域用户登录域主机记录winlog.event_data.Status:0x6 event.code:4768 or event.code:4771----------------------------------------------3.0 当日用户锁定记录event.code:4740----------------------------------------------4.0 当日登录DC失败详细记录event.code:4625----------------------------------------------4.1 当日登录DC成功详细记录(使用显式凭据登录)winlog.event_data.Status:0x0event.code:4648
配置Kibana dashboard可视化界面
当日域用户登录域主机失败记录:记录当日用户登录域主机或域控的失败次数,该数据可视为账户锁定和周期性尝试登录的依据
当日错误域用户登录域主机记录:统计使用非AD域账户登录域主机的数据
当日用户锁定记录:记录域用户使用错误密码尝试登录连续超过8次,账号被锁定
当日登录DC失败详细记录:记录当日登录域控制器失败的情况
当日登录DC成功详细记录:记录当日登录域控制器成功的情况
七. Python自动化脚本
1.主机绑定到用户(用户-主机名)
获取用户第一次登录修改密码成功,logstash收集修改密码事件4723到Elasticsearch
Python脚本周期(crontab计划任务)读取Elasticsearch日志,当读检索到修改密码事件后获取用户名、IP、主机名,并将event.code 修改为666666(用于kibana展示),最后使用ldap3模块将主机名绑定到AD域用户下
Python绑定脚本,以脚本运行在192.168.20.10(Centos7)为例,请提前搜索安装wmi
#! /usr/bin/env python3# -*- coding: utf-8 -*-# 使用前建议关闭windows客户端域防火墙import loggingimport logging.handlersimport wmi_client_wrapper as wmifrom elasticsearch import Elasticsearchfrom ldap3 import Server, Connection, ALL, MODIFY_REPLACEELASTIC_PORT = 9200ELASTIC_IP = "192.168.20.10"INDEX_NAME = "winlogbeat*"DC_SERVER = "192.168.10.10"AD_ADMIN_USER = r"test\PythonScript"AD_ADMIN_PASS = "12345678"logger = None# 日志配置:记录器、处理程序、过滤器和格式化程序def init_logger(): global logger # 创建记录器 logger = logging.getLogger('bindhost_aduser') # 指定记录器处理的最低严重性日志消息 logger.setLevel(logging.INFO) # 定义处理程序,并添加到记录器 logger_hander = logging.handlers.RotatingFileHandler( filename="/var/log/bindhost_aduser/bindhost_aduser.log", maxBytes=20*1024, backupCount=10) # logger_hander = logging.StreamHandler() logger.addHandler(logger_hander) # 格式化程序,添加到处理程序 formatter = logging.Formatter('%(asctime)s:%(name)s:%(levelname)s:%(message)s') logger_hander.setFormatter(formatter)# Python WMI 远程登录获取主机名def get_hostName(userIP): try: wmic = wmi.WmiClientWrapper( username=AD_ADMIN_USER, password=AD_ADMIN_PASS, host=userIP) hostName = wmic.query( "select * from Win32_OperatingSystem")[0]["CSName"] if "ad1" != hostName.lower() and "ad2" != hostName.lower(): return hostName else: logger.info(f"获取主机名为{hostName}") return 0 except: # 记录到日志中 logger.warning(f"wmi登录主机:{userIP} 失败!") return 0# 获取更改密码用户的IP地址def query_userIP(indexName, userName): # 查询修改密码用户的登录的主机IP QUERY_USER_IP = { "query": { "bool": { "must": [ { "term": { "event.code": 4768 } }, { "term": { "winlog.event_data.TargetUserName": userName } } ] } }, "sort": [{"@timestamp": {"order": "desc"}}] } try: queryUserIP = es.search( index=indexName, body=QUERY_USER_IP) lenResult = len(queryUserIP['hits']['hits']) if lenResult >= 1: userIP = queryUserIP['hits']['hits'][0]['_source']['user_ip'] return userIP except Exception as e: # 记录到日志 logger.exception(e) return 0# 获取更改密码用户名def query_userName(indexName): # 查询用户修改密码成功事件 QUERY_USER = { "query": { "bool": { "must": [ { "term": { "event.code": 4723 } }, { "term": { "winlog.keywords.keyword": '审核成功' } }, { "range": { "@timestamp":{ "gt": "now-30m" } } } ] } }, "sort": [{"@timestamp": {"order": "desc"}}], "size": 10 } # 绑定成功后修改事件ID,用于kibana展示绑定成功 SUCCESS_EVENT = { "doc": { "event": { "code": 666666 } } } try: queryUser = es.search(index=indexName, body=QUERY_USER) lenResult = len(queryUser['hits']['hits']) if lenResult >= 1: # 一次获取最近10个 users_list = queryUser['hits']['hits'] for user in users_list: logIndex = user['_index'] logId = user['_id'] userName = user['_source']['winlog']['event_data']['TargetUserName'] logger.info(f"捕捉AD用户:{userName} 在:{user['_source']['@timestamp']} 修改密码!") # 调用query_userIP获取用户登录IP userIP = query_userIP(indexName, userName) if userIP: # 调用get_hostName登录主机获取主机名 hostName = get_hostName(userIP) if hostName: bind_result = bind_hostName(userName, hostName) if bind_result: # 修改事件ID,用于kibana展示修改成功的用户名和主机名,主要用来检查是否绑定 es.update(index=logIndex, doc_type="_doc",id=logId, body=SUCCESS_EVENT) except Exception as e: # 记录到日志 logger.exception(e)# 将新用户绑定到修改密码的主机上,默认运维部人员(devops)不用绑定def bind_hostName(userName, hostName): server = Server(DC_SERVER, get_info=ALL) conn = Connection(server, AD_ADMIN_USER, AD_ADMIN_PASS, auto_bind=True) try: conn.search(search_base="ou=test,dc=test,dc=io", search_filter=f'(sAMAccountName={userName})', attributes=['cn', 'userWorkstations']) # 查找用户DN,如果用户未曾绑定过主机则绑定主机 user_dn = conn.response[0]["dn"] user_host = conn.response[0]["attributes"]["userWorkstations"] if user_host == [] and "devops" not in user_dn: conn.modify(user_dn, {'userWorkstations': [ (MODIFY_REPLACE, [hostName])]}) if conn.result['description'] == "success": # 打印日志 logger.info(f"绑定主机:{hostName} 到用户:{userName} 状态:{conn.result['description']}") else: logger.info(f"用户:{userName} 已经绑定或运维人员不需要绑定!") return 1 except Exception as e: # 打印日志 logger.exception(e) return 0 if __name__ == "__main__": init_logger() es = Elasticsearch( [{'host': ELASTIC_IP, 'port': ELASTIC_PORT}], timeout=3600) query_userName(INDEX_NAME)
2.Python批量创建、删除用户脚本
如有需要请发简信
八.主机加入域及用户登录
1.加域及初始化配置
确保分配到了DHCP下发的地址,DNS服务器为192.168.10.10或192.168.10.11
设置本地管理员账号密码
计算机 -> 属性 -> 高级系统设置 -> 计算机名 -> 更改 -> 隶属于 -> 域 -> test.com -> 输入域管理账号 -> 确定 -> 应用 -> 重启主机
关闭本地域防火墙
2.AD用户登录
用户名为用户的拼音全拼如张三:zhangsan
初始密码为12345678,首次登录会提示修改密码(必须符合密码复杂度要求),修改密码后即可登录
首次登录后,如果安装软件或卸载软件等提示没有权限,注销再次登录即可
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
网络打印机拒绝访问,无法连接处理方法汇总
利用组策略进行的一次Windows主机安全整改
修改windows 2003 密码策略
一份详尽的IPC$入侵资料
电脑能连上打印机,但是总是打印不了,是怎么回事?
Windows7 登陆失败:未知的用户名或密码错误 无法进入网络共享文件夹
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服