一. AD DS簡介
Active Directory域服務(wù) (AD DS) 可存儲有關(guān)網(wǎng)絡(luò)上的用戶击纬、計算機和其他資源的信息鼎姐。AD DS 可幫助管理員安全地管理此信息。還便于在用戶中實現(xiàn)共享和協(xié)作更振。AD DS 是啟用了目錄的應(yīng)用程序(如 Microsoft Exchange Server)和其他 Windows Server 技術(shù)(如組策略)所必需的。
二. 服務(wù)器
1.DC服務(wù)器
主機名 | 主機IP | 角色 | 系統(tǒng) |
---|---|---|---|
ad1.test.com | 192.168.10.10 | master1 | WindowsServer2019 |
ad2.test.com | 192.168.10.11 | master2 | WindowsServer2019 |
兩臺DC安裝Winlogbeat
2.ELK服務(wù)器
請使用三臺及以上的es來搭建群集饭尝,我這里只是實現(xiàn)了主從而并沒有實現(xiàn)高可用
主機名 | 主機IP | 角色 | 系統(tǒng) |
---|---|---|---|
ELK | 192.168.20.10 | master1 | CentOS7.5.1804 |
ELK2 | 192.168.20.11 | node1 | CentOS7.5.1804 |
三. 組織架構(gòu)
四. 配置常規(guī)組策略
1. 自動鎖屏
組策略管理編輯器 => 用戶配置 => 策略 => 管理模板 => 控制面板 => 個性化
啟用屏幕保護程序
配置為已啟用
阻止更改屏幕保護程序
配置為已啟用
帶密碼的屏幕保護程序
配置為已啟用
屏幕保護程序超時
配置為已啟用 秒:300
2.賬號密碼設(shè)置
組策略管理器編輯器 => 計算機配置 => 策略 => Windows 設(shè)置 => 安全設(shè)置 => 賬戶策略 => 密碼策略
密碼必須符合復(fù)雜性要求
:已啟用
密碼長度最小值
:8個字符
密碼最短使用期限
:0
密碼最長使用期限
:0
強制密碼歷史
:沒有定義
3.賬戶鎖定
組策略管理器編輯器 => 計算機配置 => 策略 => Windows 設(shè)置 => 安全設(shè)置 => 賬戶策略 => 賬戶鎖定策略
賬戶鎖定時間
設(shè)置為0肯腕,需管理員手動解鎖
賬戶鎖定閥值
設(shè)置為8,用戶連續(xù)輸入錯誤8次則該用戶被鎖定
重置賬戶鎖定計數(shù)器
設(shè)置為30分鐘之后钥平,表示在8次內(nèi)輸入的次數(shù)計數(shù)器在30分鐘后重置為0
4.登錄時間限制
用戶屬性 => 賬戶 => 登錄時間
5.用戶登錄指定主機(修改密碼后自動綁定)
用戶屬性 => 賬戶 => 登錄到 => 下列計算機
6.USB禁用
組策略管理編輯器 => 用戶配置 => 策略 => 管理模板 => 系統(tǒng) => 可移動存儲訪問
可移動磁盤:拒絕讀取權(quán)限
配置已啟動
7.桌面設(shè)置
組策略管理編輯器 => 用戶配置 => 策略 => 管理模板 => 桌面 => 桌面
桌面墻紙
創(chuàng)建共享实撒,將設(shè)置的用戶或組添加到照片上
注:組策略設(shè)置用戶桌面配置后,用戶無法再手動設(shè)置桌面
8.下發(fā)證書
計算機配置 => 策略 => Windows設(shè)置 => 安全設(shè)置 => 公鑰策略 => 受信任的根證書頒發(fā)機構(gòu) => 導(dǎo)入只讀共享目錄下的證書
9.msi軟件下發(fā)
組策略管理編輯器 => 用戶配置 => 策略 => 軟件設(shè)置 => 軟件安裝
新建數(shù)據(jù)包 => 選擇共享目錄下的msi文件 => 部署類型為“ 已分配” => 部署選項“在登錄時安裝此應(yīng)用程序”
10.AD用戶本地管理員權(quán)限
組策略管理編輯器 => 用戶配置 => 首選項 => 控制面板設(shè)置 => 本地用戶和組 => 新建本地組
操作:更新
組名:Administrators
添加當(dāng)前用戶涉瘾、刪除所有成員用戶知态、刪除所有成員組
添加Domain Adminis 組
五. DC安全
AD DS 服務(wù)涉及到的固定端口,同時其中組策略和RPC會使用動態(tài)TCP和UDP端口立叛,為了保證服務(wù)的可靠性负敏,我們使用防火墻默認(rèn)開通的AD DS服務(wù)的相關(guān)規(guī)則,關(guān)閉其他非相關(guān)服務(wù)秘蛇,同時入站對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. 關(guān)閉其他非相關(guān)服務(wù)規(guī)則妖泄,關(guān)鍵端口IP限制
135驹沿、389、445蹈胡、636渊季、3389端口對指定網(wǎng)段或IP放通
六. Windows安全事件日志收集
1. DC開啟身份驗證服務(wù)組策略
通常用戶每次在登錄域主機時,都會向DC的DS進(jìn)行身份認(rèn)證并由TGS頒發(fā)服務(wù)請求票據(jù)(TGT)罚渐,根據(jù)事件的event.code和winlog.event_data.Status可以篩選出用戶登錄成功和失敗以及非法登錄梭域。
參考Windows Security Log Events,這里需要用到的域主機登錄事件:
登錄情況分類 | winlog.event_data.Status | event.code |
---|---|---|
非AD用戶名登錄 | 0x6 | 4768 |
AD用戶名登錄搅轿,密碼錯誤 | 0x18 | 4771 |
AD用戶名登錄病涨,密碼正確 | 0x0 | 4768 |
一個帳戶無法登錄 | 4625 | |
嘗試使用顯式憑據(jù)登錄 | 4648 | |
用戶帳戶已被鎖定 | 4740 | |
試圖更改帳戶密碼 | 4723 |
- 組策略管理編輯器 => 計算機配置 => 策略 => Windows 設(shè)置 => 安全設(shè)置 => 高級審查策略配置 => 審核策略 => 賬戶登錄 => 審核Kerberos 身份驗證服務(wù) => 勾選 “成功” 和“失敗”
- 組策略管理編輯器 => 計算機配置 => 策略 => Windows 設(shè)置 => 安全設(shè)置 => 高級審查策略配置 => 審核策略 => 賬戶管理=> 審核用戶賬戶管理 => 勾選 “成功” 和“失敗”
- 組策略管理編輯器 => 計算機配置 => 策略 => Windows 設(shè)置 => 安全設(shè)置 => 高級審查策略配置 => 審核策略 => 登錄/注銷 => 審核登錄 => 勾選 “成功” 和“失敗”
- 打開CMD窗口輸入
gpupdate /force
強制刷新組策略 - 使用域用戶賬號登錄已加入域的主機,在AD DC上查看 事件查看器 => Windows 日志 => 安全
2. 安裝Winlogbeat + Logstash + Elasticsearch + Kibana
官網(wǎng)下載 Winlogbeat解壓包和其他RPM安裝
-
配置Winlogbeat客戶端
將Winlogbeat 收集的日志以負(fù)載均衡的方式發(fā)送到Logstash
output.logstash: # The Logstash hosts hosts: ["192.168.20.11:5044","192.168.20.10:5044"] loadbalance: true
.\winlogbeat.exe run 或 安裝啟動winlogbeat服務(wù)
配置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 host
filter {
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 host
filter {
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 elasticsearch
output {
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.yml
cluster.name: elk-cluster
node.name: ELK
network.host: 192.168.20.10
discovery.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.yml
server.host: "192.168.20.10"
i18n.locale: "zh-CN"
- 啟動服務(wù)
[root@ELK ~]# systemctl start logstash elasticsearch kibana
3. 配置 kibana dashboard
-
kibana篩選并可視化數(shù)據(jù)
1.0 當(dāng)日域用戶登錄域主機失敗記錄 winlog.event_data.Status:0x18 event.code:4771 1.1 當(dāng)日域用戶登錄域主機失敗時序圖 winlog.event_data.Status.keyword : "0x6" or (event.code: 4771 and winlog.event_data.Status.keyword : "0x18") --------------------------------------------- 2.0 當(dāng)日錯誤域用戶登錄域主機記錄 winlog.event_data.Status:0x6 event.code:4768 or event.code:4771 ---------------------------------------------- 3.0 當(dāng)日用戶鎖定記錄 event.code:4740 ---------------------------------------------- 4.0 當(dāng)日登錄DC失敗詳細(xì)記錄 event.code:4625 ---------------------------------------------- 4.1 當(dāng)日登錄DC成功詳細(xì)記錄(使用顯式憑據(jù)登錄) winlog.event_data.Status:0x0 event.code:4648
配置Kibana dashboard可視化界面
當(dāng)日域用戶登錄域主機失敗記錄:記錄當(dāng)日用戶登錄域主機或域控的失敗次數(shù)雀鹃,該數(shù)據(jù)可視為賬戶鎖定和周期性嘗試登錄的依據(jù)
當(dāng)日錯誤域用戶登錄域主機記錄:統(tǒng)計使用非AD域賬戶登錄域主機的數(shù)據(jù)
當(dāng)日用戶鎖定記錄:記錄域用戶使用錯誤密碼嘗試登錄連續(xù)超過8次幻工,賬號被鎖定
當(dāng)日登錄DC失敗詳細(xì)記錄:記錄當(dāng)日登錄域控制器失敗的情況
當(dāng)日登錄DC成功詳細(xì)記錄:記錄當(dāng)日登錄域控制器成功的情況
七. Python自動化腳本
1.主機綁定到用戶(用戶-主機名)
獲取用戶第一次登錄修改密碼成功,logstash收集修改密碼事件4723到Elasticsearch
Python腳本周期(crontab計劃任務(wù))讀取Elasticsearch日志黎茎,當(dāng)讀檢索到修改密碼事件后獲取用戶名囊颅、IP、主機名傅瞻,并將event.code 修改為666666(用于kibana展示)踢代,最后使用ldap3模塊將主機名綁定到AD域用戶下
-
Python綁定腳本,以腳本運行在192.168.20.10(Centos7)為例嗅骄,請?zhí)崆八阉靼惭bwmi
#! /usr/bin/env python3 # -*- coding: utf-8 -*- # 使用前建議關(guān)閉windows客戶端域防火墻 import logging import logging.handlers import wmi_client_wrapper as wmi from elasticsearch import Elasticsearch from ldap3 import Server, Connection, ALL, MODIFY_REPLACE ELASTIC_PORT = 9200 ELASTIC_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 # 創(chuàng)建記錄器 logger = logging.getLogger('bindhost_aduser') # 指定記錄器處理的最低嚴(yán)重性日志消息 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 遠(yuǎn)程登錄獲取主機名 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']} 修改密碼医窿!") # 調(diào)用query_userIP獲取用戶登錄IP userIP = query_userIP(indexName, userName) if userIP: # 調(diào)用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) # 將新用戶綁定到修改密碼的主機上,默認(rèn)運維部人員(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} 狀態(tài):{conn.result['description']}") else: logger.info(f"用戶:{userName} 已經(jīng)綁定或運維人員不需要綁定炊林!") 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批量創(chuàng)建姥卢、刪除用戶腳本
如有需要請發(fā)簡信
八.主機加入域及用戶登錄
1.加域及初始化配置
- 確保分配到了DHCP下發(fā)的地址,DNS服務(wù)器為192.168.10.10或192.168.10.11
- 設(shè)置本地管理員賬號密碼
- 計算機 -> 屬性 -> 高級系統(tǒng)設(shè)置 -> 計算機名 -> 更改 -> 隸屬于 -> 域 -> test.com -> 輸入域管理賬號 -> 確定 -> 應(yīng)用 -> 重啟主機
- 關(guān)閉本地域防火墻
2.AD用戶登錄
- 用戶名為用戶的拼音全拼如張三:zhangsan
- 初始密碼為12345678铛铁,首次登錄會提示修改密碼(必須符合密碼復(fù)雜度要求)隔显,修改密碼后即可登錄
- 首次登錄后却妨,如果安裝軟件或卸載軟件等提示沒有權(quán)限,注銷再次登錄即可