本文主要介绍通过Windows NPS构建RADIUS服务器的记账及后期用户流量审计
关于如何使用NPS与域控集成认证,可以参照前一篇文章
Windows Server NPS服务构建基于AD域控的radius认证
本文涉及的知识点:
1、NPS记账功能
2、Microsoft AD集成认证
3、SQL Server部署
4、SQL 存储过程修改
5、三层设备SNMP配置
6、三层路由设备Snmp ARP获取
7、Python 连接SQL Server
8、Python OS包获取操作系统指令
9、Python字符串处理,截取和拼接
10、行为审计设备操作
鬼知道为什么要用到这么多知识点
本文用的到知识点跨专业比较大,各位同学选择你感兴趣的点看就好。
贼简单,一路Next就好,下方放出MSDN Itell you的连接
SQL Server 2016 Developer with Service Pack 2 (x64) - DVD (Chinese-Simplified)
ed2k://|file|cn_sql_server_2016_developer_with_service_pack_2_x64_dvd_12195013.iso|3217154048|AC379F2A852760E54316A2CDAEFCB42C|/
运行SQL Server 2016 Master Data Services Configuration Manager
新建数据库
贼简单,一路Next就好,下方放出下载链接
Microsoft | 下载 SQL Server Management Studio (SSMS)
官方手册
Microsoft | Configure Network Policy Server Accounting
建议勾选同时记录到SQL Server和本地文本文件
配置记账数据库连接信息
配置本地文件日志记录
初始化数据库,点击重新生成
选择启用文本文件日志记录进行故障转移
,避免因SQL Server故障导致RADIUS拒绝认证
此表默认包含以下字段
大部分字段都是字面意思,具体需要解释的,参阅以下文档
Microsoft | Interpret NPS Database Format Log Files
Timestamp,
Computer_Name,
Packet_Type,
User_Name,
Client_IP_Address,
Fully_Qualified_Machine_Name,
NP_Policy_Name,
MS_Quarantine_State,
MS_Extended_Quarantine_State,
SystemHealthResult,
SystemHealthResultEx,
MS_Network_Access_Server_Type,
Called_Station_Id,
MS_Quarantine_Grace_Time,
MS_Quarantine_User_Class,
Client_IPv6_Address,
Not_Quarantine_Capable,
AFW_Zone,
AFW_Protection_Level,
Quarantine_Update_Non_Compliant,
MS_Machine_Name,
OS_Version,
MS_Quarantine_Session_Id
NPS 将记帐数据格式化为 XML 文档,该文档将其发送到你在 NPS 中指定的 SQL Server 数据库中的report_event存储过程。 若要使 SQL Server 日志记录正常工作,SQL Server 数据库中必须有一个名为report_event的存储过程,该存储过程可接收和分析 NPS 中的 XML 文档。
通过修改dbo.report_event存储过程,我们可以将我们感兴趣的字段加入数据库并进行记录
USE [NPS]
GO
/****** Object: StoredProcedure [dbo].[report_event] Script Date: 2020/3/9 20:36:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[report_event]
@doc ntext
AS
SET NOCOUNT ON
DECLARE @idoc int
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
/*
Combine multiple System-Health-Result string into one string with delimiter as ":"
*/
DECLARE @SystemHealthResult NVARCHAR(4000)
SELECT @SystemHealthResult = COALESCE(@SystemHealthResult+':','')+ISNULL(SHR.System_Health_Result,'')
FROM (SELECT *
FROM OPENXML(@idoc, '/Event/System-Health-Result')
WITH (System_Health_Result NVARCHAR(4000) 'text()')) AS SHR
/*
Combine multiple System-Health-ResultEx string into one string
*/
DECLARE @SystemHealthResultEx NVARCHAR(MAX)
IF @SystemHealthResult IS NOT NULL SELECT @SystemHealthResultEx = COALESCE(@SystemHealthResultEx,'')+ISNULL(CAST(SHR.System_Health_ResultEx AS NVARCHAR(MAX)),'')
FROM (SELECT *
FROM OPENXML(@idoc, '/Event/System-Health-ResultEx')
WITH (System_Health_ResultEx xml '.')) AS SHR
/*
All RADIUS attributes written to the ODBC format logfile are declared here. Refer to IAS ODBC Formatted Log Files in Online Help for information on interpreting these values.
*/
INSERT accounting_data
SELECT
Timestamp,
Computer_Name,
Packet_Type,
[User_Name],
Client_IP_Address,
Fully_Qualified_Machine_Name,
NP_Policy_Name,
MS_Quarantine_State,
MS_Extended_Quarantine_State,
@SystemHealthResult,
@SystemHealthResultEx,
MS_Network_Access_Server_Type,
Called_Station_Id,
Calling_Station_Id,
MS_Quarantine_Grace_Time,
MS_Quarantine_User_Class,
Client_IPv6_Address,
Not_Quarantine_Capable,
AFW_Zone,
AFW_Protection_Level,
Quarantine_Update_Non_Compliant,
MS_Machine_Name,
OS_Version,
MS_Quarantine_Session_Id
FROM OPENXML(@idoc, '/Event')
WITH (
Timestamp datetime './Timestamp',
Computer_Name nvarchar(255) './Computer-Name',
Packet_Type int './Packet-Type',
[User_Name] nvarchar(255) './User-Name',
Client_IP_Address nvarchar(15) './Client-IP-Address',
Fully_Qualified_Machine_Name nvarchar(255) './Fully-Qualified-Machine-Name',
NP_Policy_Name nvarchar(255) './NP-Policy-Name',
MS_Quarantine_State int './MS-Quarantine-State',
MS_Extended_Quarantine_State int './MS-Extended-Quarantine-State',
System_Health_Result nvarchar(4000),
System_Health_ResultEx nvarchar(MAX),
MS_Network_Access_Server_Type int './MS-Network-Access-Server-Type',
Called_Station_Id nvarchar(255) './Called-Station-Id',
Calling_Station_Id nvarchar(255) './Calling-Station-Id',
MS_Quarantine_Grace_Time datetime './MS-Quarantine-Grace-Time',
MS_Quarantine_User_Class nvarchar(255) './MS-Quarantine-User-Class',
Client_IPv6_Address nvarchar(32) './Client-IPv6-Address',
Not_Quarantine_Capable int './Not-Quarantine-Capable',
AFW_Zone int './AFW-Zone',
AFW_Protection_Level int './AFW-Protection-Level',
Quarantine_Update_Non_Compliant int './Quarantine-Update-Non-Compliant',
MS_Machine_Name nvarchar(255) './MS-Machine-Name',
OS_Version nvarchar(255) './Machine-Inventory',
MS_Quarantine_Session_Id nvarchar(255) './MS-Quarantine-Session-Id'
)
EXEC sp_xml_removedocument @idoc
SET NOCOUNT OFF
CREATE TALBE加入[Calling_Station_Id] [nvarchar](255) NULL,
然后点执行!
认证设备MAC地址一般在RADIUS认证报文中以Calling Station ID
字段进行传输。
但是NPS默认记账不记录Calling Station ID
字段,我们需要修改dbo.report_event
存储过程,添加数据库记录字段。
INSERT语句添加Calling_Station_Id,
XML解释添加Calling_Station_Id nvarchar(255) './Calling-Station-Id',
然后点执行!
查看dbo.accounting_data
表,可以看到用户认证终端的MAC地址,记录在Calling_Station_Id
字段中
通过上述操作,我们获取了认证后的用户MAC address—User_Name的对应关系。
但是很多行为审计设备要求获取IP Address—User_Name的对应关系。
因此我们需要一些办法,获取MAC address—IP Address的对应关系。
那这不就是ARP表么!
我也不知道看这边文章的同学,你们是搞服务器运维的,还是搞数据库的,还是搞网络的。有些同学不知道SNMP,简单介绍一下
虽然不同的厂商设备OID会相差很大,因此厂商通常会提供MIB库来检索OID
但是,对于获取ARP表有一个通用的OID:
OID 1.3.6.1.2.1.4.22.1.2
使用walk方法可以跑出全部端口的ARP表
linux和windows均有snmpwalk安装程序
Linux:yum install -y net-snmp net-snmp-utils
windows下安装net-snmp,我们可以去net-snmp官网进行下载。
http://www.net-snmp.org/download.html
安装方法CSDN上一大堆,比如其他大大们的指导
https://blog.csdn.net/weixin_30752699/article/details/98688984
HUAWEI H3C CISCO百度搜索一下方法一大堆
举例H3C:
<H3C>dis cu | in snmp
snmp-agent
snmp-agent local-engineid 800063A28008688D43D19600000001
snmp-agent community read wulalalwulalala
snmp-agent sys-info version v2c v3
snmp-server arp-sync enable
举例HUAWEI
<HUAWEI>dis cu | in snmp
snmp-agent
snmp-agent local-engineid 800007DB03A4BE2B3B80A0
snmp-agent community read cipher %^%#Myph,aG8/Ke]v1'gt@G#+W]EVCBrGQ]:>YDShMB#QjT`Phq'R8)OvPNrHANLf[(;L_<^-:o0/nJ*S5rE%^%#
snmp-agent sys-info version v2c v3
举例Aruba
(Aruba-AC) *[mynode] #show running-config | include snmp
Building Configuration...
netservice svc-snmp udp 161
netservice svc-snmp-trap udp 162
ipv6 any user svc-snmp permit
ipv6 user any svc-snmp-trap permit
any user svc-snmp permit
user any svc-snmp-trap permit
snmp-server community "jiubugaosuniwodemima"
snmp-server enable trap
snmp-server trap source 0.0.0.0
举例CISCO
Router# configure terminal
Router(config)# snmp-server community aishashajiushibushuo ro
Router(config)# snmp-server trap link ietf
Router(config)# snmp-server enable traps snmp
以Linux为例
snmpwalk -v 2c -c snmp秘钥 设备IP地址 1.3.6.1.2.1.4.22.1.2
够直白的ARP表,如下图所示
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.12 = STRING: 94:a4:ac:74:5b:2c
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.13 = STRING: 94:a4:ac:74:5d:18
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.14 = STRING: 94:a4:ac:60:49:74
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.15 = STRING: 58:a4:fb:5b:fd:81
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.16 = STRING: 94:a4:ac:74:5a:e6
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.17 = STRING: 94:a4:ac:74:58:cd
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.18 = STRING: 94:a4:ac:74:5a:f5
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.19 = STRING: 64:a4:8b:65:c1:f2
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.20 = STRING: 64:a4:8b:65:c3:a1
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.21 = STRING: 64:a4:8b:65:bd:95
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.22 = STRING: 64:a4:8b:65:c3:a7
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.23 = STRING: 64:a4:8b:65:c2:3
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.24 = STRING: 68:a4:bc:25:85:57
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.25 = STRING: 68:a4:bc:25:83:ac
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.26 = STRING: 68:a4:bc:25:83:c7
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.27 = STRING: 68:a4:bc:25:83:b7
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.28 = STRING: 68:a4:bc:25:85:df
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.29 = STRING: 68:a4:bc:25:85:da
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.32 = STRING: 60:a4:a4:5e:fc:a4
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.34 = STRING: 0a:a4:56:8b:58:74
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.35 = STRING: 0a:a4:29:f9:98:7c
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.37 = STRING: 60:a4:a4:7c:73:8e
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.39 = STRING: 60:a4:a4:7c:65:e
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.45 = STRING: b8:a4:eb:c5:83:28
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.150 = STRING: 58:a4:fb:cc:52:5d
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.151 = STRING: b4:a4:82:db:f6:3
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.251 = STRING: 0a:a4:61:11:f1:de
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.252 = STRING: 0a:a4:61:10:f2:ad
IP-MIB::ipNetToMediaPhysAddress.828.10.153.146.253 = STRING: 0a:a4:61:10:9b:7f
找台linux服务器,Windows也行,随便你
安装Python和pymssql包
yum install python
pip install pymssql
特别注意Windows下pip install pymssql需要VC++运行环境,嫌麻烦不想安装VC++的话,可以如下操作
1、先去 https://www.lfd.uci.edu/~gohlke/pythonlibs/#pymssql
上面下载对应Windows操作系统版本和python版本的安装包
2、放到安装目录下,然后使用命令进入这个目录
3、执行pip3 install --user pymssql-2.1.4-cp38-cp38-win_amd64.whl
# encoding=utf-8
import pymssql
import commands
import re
import os
import sys
import datetime
server1 = "10.153.20.228"
server2 = "10.153.20.229"
#主备两台RADIUS的地址,如果你所在的环境就一个的话,删除掉多余的就行
user = "sa"
password = "数据库密码"
database = "NPS"
#数据库连接信息
conn = pymssql.connect(server1, user, password, database)
conn2 = pymssql.connect(server2, user, password, database)
cursor = conn.cursor()
cursor2 = conn2.cursor()
#构建数据库connect和cursor
def execComand(command):
#执行命令,获取返回结果
data = commands.getoutput(command)
return data
#-------------------------------------------------------------------------------
#定义一个函数,处理SNMPWALK返回的数据
def format_result(result_txt):
#原格式是这样的:
#IP-MIB::ipNetToMediaPhysAddress.828.10.153.21.253 = STRING: 0a:17:1:10:9b:7f(注意这个MAC地址没有补零)
#IP-MIB::ipNetToMediaPhysAddress.828.10.153.21.28 = STRING: 68:6d:a4:25:85:df
result_out=result_txt.replace("IP-MIB::ipNetToMediaPhysAddress.","")
result_out=result_out.replace("STRING:","")
result_out=result_out.replace(" ","")
result_out=result_out.split('\n')
#以上四句,该删的删,该替换的替换
i=0
for result_line in result_out:
result_line=result_line[4:]
result_line=result_line.split('=')
mac_addr=result_line[1].split(':')
i2=0
for mac in mac_addr:
mac_addr[i2]=mac_addr[i2].zfill(2)
#snmpwalk工具返回的MAC地址没有补零,需要进行补零操作
#0:17:1:2a:9b:7f 变换成 00:17:01:2a:9b:7f
i2=i2+1
result_line[1]="".join(mac_addr)
result_out[i]=result_line
i=i+1
return result_out
#-------------------------------------------------------------------------------
#定义一个函数,在数据库里创建ARP表
def CreateTable():
sql = """
IF OBJECT_ID('arp', 'U') IS NOT NULL DROP TABLE arp
CREATE TABLE arp (ip VARCHAR(100),mac VARCHAR(100))
"""
cursor.execute(sql)
conn.commit()
cursor2.execute(sql)
conn2.commit()
#-------------------------------------------------------------------------------
#定义一个函数,在ARP表里插入数据
def InsertData(ip,mac):
sql = "INSERT INTO arp(ip,mac) VALUES ('"+ip+"', '"+mac+"')"
cursor.execute(sql)
conn.commit()
cursor2.execute(sql)
conn2.commit()
def main():
command='snmpwalk -v 2c -c snmpsharekeyshshsh 10.153.137.1 1.3.6.1.2.1.4.22.1.2'
#linux下执行snmp的脚本命令
#如果是windows平台,使用下面这两句,并且不需要def execComand函数
#command=os.popen(" C:/usr/bin/snmpwalk.exe -v 2c -c snmpsharekeyshshsh 10.1.1.1 1.3.6.1.2.1.4.22.1.2")
#data=command.read()
data=execComand(command)
data=format_result(data)
#获取命令返回的结果,并且进行格式化处理
now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
CreateTable()
#创建一个表
InsertData(now_time,"Update Time")
#插入当前时间,用于监控平台监控ARP表更新状态
for data_sub in data:
InsertData(data_sub[0],data_sub[1])
#写入ARP表数据
if __name__ == '__main__':
main()
select * from arp
可以看到ARP表正常更新
以下语句通过计算Update_Time与现在时间差值可以监控ARP表是否正常更新
select datediff(s,ip,GETDATE()) from arp where mac='Update Time'
[root@sz_radius_10 ~]# crontab -l
*/1 * * * * /root/AC-SQL-ARP/ARP-SQL.sh
[root@sz_radius_10 ~]#
[root@sz_radius_10 ~]# cat /root/AC-SQL-ARP/ARP-SQL.sh
#!/bin/bash
cd /root/AC-SQL-ARP/
python ARP-TO-SQL.py
#---------------------------------------------------------
select timestamp,id,User_Name,mac,ip from accounting_data,arp where
(
id in
(SELECT max(id) from accounting_data group by Calling_Station_Id)
#查询同一个Calling_Station_Id最后更新的记录id
and
replace(Calling_Station_Id,'-','')=mac
#HUAWEI和H3C设备带过来的MAC地址会携带“-”,需要去除
)
order by timestamp
CREATE VIEW [dbo].[userip]
AS
select User_Name,ip from accounting_data,arp where
(
id in
(SELECT max(id) from accounting_data group by Calling_Station_Id)
and
replace(Calling_Station_Id,'-','')=mac
)
union all
(select user_name collate Chinese_PRC_CI_AI_WS,ip from user__ip where ip<>'Update Time')
#如果还有其他表,可以使用union all联合查询,没有的话,忽略上面两句
以深信服行为审计设备为例
数据库服务器选择刚才新添加的数据库服务器
查询语句:select * from userip
测试一下有效性
认证范围填写用户终端地址段。
认证方式选项卡内,认证方式选择单点登录。同时单点登录失败的用户配置使用以IP地址作为用户名。
配置完成之后,目前到达行为审计设备的流量,会触发此条认证策略创建用户。
并且,会通过之前关联的认证数据库,自动获取用户名并创建用户!!