WLAN ルーター偽装を検出するための取得データを使用した深層ニューラル ネットワークのテスト
この例では、取得データを使用して無線周波数 (RF) 指紋の畳み込みニューラル ネットワーク (CNN) の学習を行う方法を示します。ソフトウェア無線 (SDR) を使用して、実際のルーターから無線ローカル エリア ネットワーク (WLAN) ビーコン フレームを取得します。SDR をもう 1 つプログラムして未知のビーコン フレームを送信し、それらを取得します。それらの取得した信号で CNN の学習を行います。その後、ルーター偽装者として既知のいずれかのルーターのメディア アクセス制御 (MAC) アドレスでビーコン信号を送信するソフトウェア無線 (SDR) をプログラムし、それを CNN を使用して偽装者として識別します。
ルーター偽装およびシミュレーション データを使用したネットワーク設計の検証の詳細については、WLAN ルーター偽装を検出するためのシミュレーション データを使用した深層ニューラル ネットワークの設計の例を参照してください。
取得データを使用した学習
実際の WLAN ルーターから、802.11a/g/n/ac OFDM 非高スループット (非 HT) ビーコン フレームのデータセットを収集します。WLAN ルーター偽装を検出するためのシミュレーション データを使用した深層ニューラル ネットワークの設計の例で説明しているように、データ依存性を回避するため、プリアンブルのレガシ ロング トレーニング フィールド (L-LTF) のみが学習単位として使用されます。
この例では、次の図に示すシナリオを使用してデータが収集されています。オブザーバーは固定された ADALM-PLUTO 無線機です。既知のルーターのデータは次のようにして収集しました。
ルーターで使用される WLAN チャネルに基づいてオブザーバーの中心周波数を設定
ビーコン フレームを受信
L-LTF 信号を抽出
MAC アドレスを復号化してラベルとして使用
L-LTF 信号をそのラベルと共に保存
手順 2 ~ 5 を繰り返して
numKnownRouters
のルーターからnumFramesPerRouter
フレームを収集
未知のルーターのビーコン フレームのシミュレーションでは、移動する ADALM-PLUTO 無線機を送信機として使用しています。この無線機からランダムな MAC アドレスでビーコン フレームを繰り返し送信します。未知のルーターのデータは次のようにして収集しました。
ランダムな MAC アドレスでビーコン フレームを生成
ADALM-PLUTO 無線機を使用したビーコン フレームの繰り返し送信を開始
NUMFRAMES
のビーコン フレームを収集L-LTF 信号を抽出
L-LTF フレームをラベル "Unknown" で保存
無線機を別の位置に移動
手順 3 ~ 6 を繰り返して
NUMLOC
の位置からデータを収集
この既知と未知のルーターを組み合わせたデータセットを使用して、WLAN ルーター偽装を検出するためのシミュレーション データを使用した深層ニューラル ネットワークの設計の例と同じ DL モデルの学習を行います。
この例では、学習データと学習済みネットワークを https://www.mathworks.com/supportfiles/spc/RFFingerprinting/RFFingerprintingCapturedData_R2024b.tar からダウンロードします。インターネット接続がない場合は、インターネットに接続したコンピューターで手動でファイルをダウンロードし、この例のファイルと同じディレクトリに保存してください。プライバシー上の理由から、ダウンロード データ内の MAC アドレスは匿名化されています。この例の結果を再現するには、次の付録の説明に従って独自のデータを取得してください。付録: 既知および未知のルーターのデータの収集。
rfFingerprintingDownloadData('captured')
Starting download of data files from: https://www.mathworks.com/supportfiles/spc/RFFingerprinting/RFFingerprintingCapturedData_R2024b.tar Download and extracting files done
この例を迅速に実行するには、ダウンロードした事前学習済みのネットワークを使用します。コンピューターでネットワークに学習させるには、"Train network now" オプションを選択します (つまり、trainNow
を true に設定します)。このネットワークの学習にかかる時間は、NVIDIA® GeForce RTX 3080 GPU で約 25 秒、Intel® Xeon W-2133 CPU @ 3.6 GHz で約 2 分です。
trainNow =false; %#ok<*UNRCH>
この例では、4 台の既知のルーターのデータを使用します。データセットにはルーターあたり 3600 のフレームが含まれており、その 90% を学習フレームとして使用し、10% をテスト フレームとして使用します。
numKnownRouters = 4; numFramesPerRouter = 3600; numTrainingFramesPerRouter = numFramesPerRouter * 0.9; numTestFramesPerRouter = numFramesPerRouter * 0.1; frameLength = 160;
既知および未知のルーターのデータの前処理
収集した複素ベースバンド データを同相成分と直交成分に分割し、frameLength x 2 x 1 x numFramesPerRouter*numKnownRouters の行列に形状変更します。未知のルーターのデータについて同じ処理を繰り返します。次のコードでは、前に収集した事前処理済みのデータを使用しています。独自のデータを使用するには、先に次の付録の説明に従ってデータを収集します。付録: 既知および未知のルーターのデータの収集。rfFingerprintingCapturedDataUser.mat
および rfFingerprintingCapturedUnknownFramesUser.mat
という名前の新しいデータ ファイルをこの例と同じディレクトリにコピーします。その後、それらのファイルを読み込むように load
コマンドを更新します。
if trainNow % Load known router data load('rfFingerprintingCapturedData.mat') % Create label vectors yTrain = repelem(MACAddresses.',numTrainingFramesPerRouter); yTest = repelem(MACAddresses.',numTestFramesPerRouter); % Separate between I and Q numTrainingSamples = numTrainingFramesPerRouter*numKnownRouters*frameLength; xTrainingFrames = xTrainingFrames(1:numTrainingSamples,1); xTrainingFrames = [real(xTrainingFrames),imag(xTrainingFrames)]; numTestSamples = numTestFramesPerRouter*numKnownRouters*frameLength; xTestFrames = xTestFrames(1:numTestSamples,1); xTestFrames = [real(xTestFrames),imag(xTestFrames)]; % Reshape dataset into an frameLength x 2 x 1 x numTrainingFramesPerRouter*numKnownRouters matrix xTrainingFrames = permute(reshape(xTrainingFrames,[frameLength,numTrainingFramesPerRouter*numKnownRouters,2,1]),[1 3 4 2]); % Reshape dataset into an frameLength x 2 x 1 x numTestFramesPerRouter*numKnownRouters matrix xTestFrames = permute(reshape(xTestFrames,[frameLength,numTestFramesPerRouter*numKnownRouters,2,1]),[1 3 4 2]); % Load unknown router data load('rfFingerprintingCapturedUnknownFrames.mat') % Number of training units numUnknownFrames = size(unknownFrames,4); % Split data into 90% training and 10% test numUnknownTrainingFrames = floor(numUnknownFrames*0.9); numUnknownTest = numUnknownFrames - numUnknownTrainingFrames; % Add ADALM-PLUTO data into training and test datasets xTrainingFrames(:,:,:,(1:numUnknownTrainingFrames) + numTrainingFramesPerRouter*numKnownRouters) = unknownFrames(:,:,:, 1:numUnknownTrainingFrames); xTestFrames(:,:,:,(1:numUnknownTest) + numTestFramesPerRouter*numKnownRouters) = unknownFrames(:,:,:,(1:numUnknownTest) + numUnknownTrainingFrames); % Shuffle data vr = randperm(numKnownRouters*numTrainingFramesPerRouter+numUnknownTrainingFrames); xTrainingFrames = xTrainingFrames(:,:,:,vr); % Add "unknown" label and shuffle yTrain = [yTrain; repmat("Unknown",[numUnknownTrainingFrames,1])]; MACAddresses = unique(yTrain(vr)); % List of unique MAC addresses for prediction yTrain = categorical(yTrain(vr)); yTest = [yTest; repmat("Unknown",[numUnknownTest,1])]; yTest = categorical(yTest); uniqueMACAddresses = unique(yTrain); end
CNN の学習
シミュレーション データを使用した学習の例と同じ NN アーキテクチャと学習オプションを使用します。
poolSize = [2 1]; strideSize = [2 1]; layers = [ imageInputLayer([frameLength 2 1],'Normalization','none','Name','Input Layer') convolution2dLayer([7 1],50,'Padding',[1 0],'Name','CNN1') batchNormalizationLayer('Name','BN1') leakyReluLayer('Name','LeakyReLu1') maxPooling2dLayer(poolSize,'Stride',strideSize,'Name','MaxPool1') convolution2dLayer([7 2],50,'Padding',[1 0],'Name','CNN2') batchNormalizationLayer('Name','BN2') leakyReluLayer('Name','LeakyReLu2') maxPooling2dLayer(poolSize,'Stride',strideSize,'Name','MaxPool2') fullyConnectedLayer(256,'Name','FC1') leakyReluLayer('Name','LeakyReLu3') dropoutLayer(0.5,'Name','DropOut1') fullyConnectedLayer(80,'Name','FC2') leakyReluLayer('Name','LeakyReLu4') dropoutLayer(0.5,'Name','DropOut2') fullyConnectedLayer(numKnownRouters+1,'Name','FC3') softmaxLayer('Name','SoftMax') ]
layers = 17×1 Layer array with layers: 1 'Input Layer' Image Input 160×2×1 images 2 'CNN1' 2-D Convolution 50 7×1 convolutions with stride [1 1] and padding [1 1 0 0] 3 'BN1' Batch Normalization Batch normalization 4 'LeakyReLu1' Leaky ReLU Leaky ReLU with scale 0.01 5 'MaxPool1' 2-D Max Pooling 2×1 max pooling with stride [2 1] and padding [0 0 0 0] 6 'CNN2' 2-D Convolution 50 7×2 convolutions with stride [1 1] and padding [1 1 0 0] 7 'BN2' Batch Normalization Batch normalization 8 'LeakyReLu2' Leaky ReLU Leaky ReLU with scale 0.01 9 'MaxPool2' 2-D Max Pooling 2×1 max pooling with stride [2 1] and padding [0 0 0 0] 10 'FC1' Fully Connected 256 fully connected layer 11 'LeakyReLu3' Leaky ReLU Leaky ReLU with scale 0.01 12 'DropOut1' Dropout 50% dropout 13 'FC2' Fully Connected 80 fully connected layer 14 'LeakyReLu4' Leaky ReLU Leaky ReLU with scale 0.01 15 'DropOut2' Dropout 50% dropout 16 'FC3' Fully Connected 5 fully connected layer 17 'SoftMax' Softmax softmax
ミニバッチ サイズが 256 の ADAM オプティマイザーを使用するように学習オプションを構成します。ハイパーパラメーターの最適化が [1] で行われているため、テスト フレームを検証に使用します。
既定では、'ExecutionEnvironment
' は 'auto'
に設定されており、利用可能な場合は GPU が学習に使用されます。そうでない場合、trainnet
(Deep Learning Toolbox)では CPU が学習に使用されます。実行環境を明示的に設定するには、ExecutionEnvironment
を 'cpu'
、'gpu'
、'multi-gpu'
、または 'parallel'
のいずれかに設定します。
if trainNow miniBatchSize = 256; iterPerEpoch = floor((numTrainingFramesPerRouter*numKnownRouters + numUnknownTrainingFrames)/miniBatchSize); % Training options options = trainingOptions('adam', ... 'MaxEpochs', 12, ... 'ValidationData', {xTestFrames, yTest}, ... 'ValidationFrequency', iterPerEpoch, ... 'Verbose', false, ... 'InitialLearnRate', 0.002, ... 'LearnRateSchedule','piecewise', ... 'LearnRateDropFactor', 0.5, ... 'LearnRateDropPeriod', 2, ... 'MiniBatchSize', miniBatchSize, ... 'Plots', 'training-progress', ... 'Shuffle', 'every-epoch', ... 'Metrics', "accuracy", ... 'ExecutionEnvironment', "auto"); % Train the network capturedDataNet = trainnet(xTrainingFrames,yTrain,layers,"crossentropy",options); else load('rfFingerprintingCapturedDataTrainedNN_R2024b.mat','capturedDataNet','xTestFrames','yTest','uniqueMACAddresses') end
単一の NVIDIA GeForce RTX 3080 GPU を搭載したコンピューターでネットワークに学習させた場合の進行状況。このネットワークは 12 エポックで 100% の正確性に収束しています。
混同行列を生成します。
figure yTestPred = predict(capturedDataNet,xTestFrames); yLabel = scores2label(yTestPred,uniqueMACAddresses); cm = confusionchart(yTest,yLabel); cm.Title = 'Confusion Matrix for Test Data'; cm.RowSummary = 'row-normalized';
SDR によるテスト
分類 "Unknown" に対する学習済みネットワークの性能をテストします。既知のルーターと 1 台の未知のルーターの MAC アドレスでビーコン フレームを生成します。それらのフレームを ADALM-PLUTO 無線機を使用して送信し、別の ADALM-PLUTO 無線機を使用して受信します。それらの 2 台の無線機の間で作成されるチャネル障害と RF 劣化要因は実際のルーターとオブザーバーの間で作成されるものと異なるため、ニューラル ネットワークではすべての受信信号が "Unknown" と分類されるはずです。受信した MAC アドレスが既知の場合、システムは送信元をルーター偽装者として宣言します。受信した MAC アドレスが未知の場合、システムは送信元を未知のルーターとして宣言します。このテストを実行するには、送信用と受信用に 2 台の ADALM-PLUTO 無線機が必要です。また、Communication Toolbox Support Package for ADALM-PLUTO Radio をインストールする必要があります。
波形生成
異なる MAC アドレスのビーコン フレームで構成される送信波形を生成します。それらの WLAN フレームを送信機から繰り返し送信します。受信機で WLAN フレームを取得し、受信した MAC アドレスと学習済み NN で検出された RF 指紋を使用してルーター偽装者であるかどうかを判別します。
chanBW='CBW20'; % Channel Bandwidth osf = 2; % Oversampling Factor frameLength=160; % Frame Length in samples % Create Beacon frame-body configuration object frameBodyConfig = wlanMACManagementConfig; % Create Beacon frame configuration object beaconFrameConfig = wlanMACFrameConfig('FrameType','Beacon'); beaconFrameConfig.ManagementConfig = frameBodyConfig; % Create interpolation and decimation objects decimator = dsp.FIRDecimator('DecimationFactor',osf); % Save known MAC addresses MACAddressesToSimulate = ["71B63A2D0B83"; "A3F8AC0F2253"; "EF11D125044A"; "F636A97E07E7"; "ABCDEFABCDEF"]; % Create WLAN waveform with the MAC addresses of known routers and an unknown router txWaveform = zeros(1540,5); for i = 1:length(MACAddressesToSimulate) % Set MAC Address beaconFrameConfig.Address2 = MACAddressesToSimulate(i); % Generate Beacon frame bits [beacon, mpduLength] = wlanMACFrame(beaconFrameConfig,'OutputFormat','bits'); nonHTcfg = wlanNonHTConfig('ChannelBandwidth',chanBW,"MCS",1,"PSDULength",mpduLength); txWaveform(:,i) = [wlanWaveformGenerator(beacon, nonHTcfg); zeros(20,1)]; end txWaveform = txWaveform(:); % Get center frequency for channel 153 in 5 GHz band fc = wlanChannelFrequency(153,5); fs = wlanSampleRate(nonHTcfg); txSig = resample(txWaveform,osf,1); % Samples per frame in Burst Mode spf = length(txSig)/length(MACAddressesToSimulate); runSDRSection = false; if helperIsPlutoSDRInstalled() radios = findPlutoRadio(); if length(radios) >= 2 runSDRSection = true; else disp("Two ADALM-PLUTO radios are needed. Skipping SDR test.") end else disp("Communications Toolbox Support Package for Analog Devices ADALM-PLUTO Radio not found.") disp("Click Add-Ons in the Home tab of the MATLAB toolstrip to install the support package.") disp("Skipping SDR test.") end
Communications Toolbox Support Package for Analog Devices ADALM-PLUTO Radio not found.
Click Add-Ons in the Home tab of the MATLAB toolstrip to install the support package.
Skipping SDR test.
if runSDRSection % Set up PlutoSDR transmitter deviceNameSDR = 'Pluto'; txGain = 0; txSDR = sdrtx(deviceNameSDR); txSDR.RadioID = 'usb:0'; txSDR.BasebandSampleRate = fs*osf; txSDR.CenterFrequency = fc; txSDR.Gain = txGain; % Set up PlutoSDR Receiver rxSDR = sdrrx(deviceNameSDR); rxSDR.RadioID = 'usb:1'; rxSDR.BasebandSampleRate = txSDR.BasebandSampleRate; rxSDR.CenterFrequency = txSDR.CenterFrequency; rxSDR.GainSource ='Manual'; rxSDR.Gain = 30; rxSDR.OutputDataType = 'double'; rxSDR.EnableBurstMode=true; rxSDR.NumFramesInBurst = 20; rxSDR.SamplesPerFrame = osf*spf; end
分類用の L-LTF
各ビーコン フレームのプリアンブルにある L-LTF シーケンスを NN への入力単位として使用します。rfFingerprintingNonHTFrontEnd
System object™ を使用して、WLAN パケットの検出、同期タスクの実行、および L-LTF シーケンスとデータの抽出が行われます。また、MAC アドレスの復号化も行われます。さらに、データが前処理され、学習済みネットワークを使用して分類されます。
if runSDRSection numLLTF = 20; % Number of L-LTF captured for Testing rxFrontEnd = rfFingerprintingNonHTFrontEnd('ChannelBandwidth','CBW20'); disp("The known MAC addresses are:"); disp(knownMACAddresses) % Set PlutoSDR to transmit repeatedly disp('Starting transmitter') transmitRepeat(txSDR, txSig); % Captured Frames counter numCapturedFrames = 0; disp('Starting receiver') % Loop until numLLTF frames are collected while numCapturedFrames < numLLTF % Receive data using PlutoSDR rxSig = rxSDR(); rxSig = decimator(rxSig); % Perform front-end processing and payload buffering [payloadFull,cfgNonHT,rxNonHTData,chanEst,noiseVar,LLTF] = rxFrontEnd(rxSig); if payloadFull % Recover payload bits recBits = wlanNonHTDataRecover(rxNonHTData,chanEst,noiseVar,cfgNonHT,'EqualizationMethod','ZF'); % Decode and evaluate recovered bits [mpduCfg,~,success] = wlanMPDUDecode(recBits,cfgNonHT); if success == wlanMACDecodeStatus.Success % Update counter numCapturedFrames = numCapturedFrames+1; % Create real-valued input LLTF = [real(LLTF),imag(LLTF)]; LLTF = permute(reshape(LLTF,frameLength,[],2,1), [1 3 4 2]); ypred = classify(capturedDataNet,LLTF); if sum(contains(knownMACAddresses, mpduCfg.Address2)) ~= 0 if categorical(convertCharsToStrings(mpduCfg.Address2))~=ypred disp(strcat("MAC Address ",mpduCfg.Address2," is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED")) else disp(strcat("MAC Address ",mpduCfg.Address2," is known, fingerprint match")) end else disp(strcat("MAC Address ",mpduCfg.Address2," is not recognized, unknown device")); end end end end release(txSDR) end
その他の調査
次の付録の説明に従って独自のルーターからデータを取得します。付録: 既知および未知のルーターのデータの収集。そのデータでニューラル ネットワークの学習を行い、ネットワークの性能をテストします。
付録: 既知および未知のルーターのデータの収集
既知の (信頼済み) ルーターのデータの収集には rfFingerprintingRouterDataCollection
を使用します。この関数は、商用の 802.11 ハードウェアから送信された 802.11a/g/n/ac OFDM 非 HT ビーコン フレームから L-LTF 信号を抽出します。詳細については、WLAN Beacon Receiver Using Software-Defined Radio (WLAN Toolbox)の例を参照してください。L-LTF 信号と対応するルーターの MAC アドレスを使用して、RF 指紋のニューラル ネットワークの学習を行います。この方法は、ルーターとそのアンテナが固定されていて、意図せずに動くことはほとんどない場合に特に効果的です。たとえば、ほとんどのオフィス環境では、ルーターは天井に取り付けられています。次の手順に従います。
ADALM-PLUTO 無線機をオブザーバー無線機として使用する PC に接続します。
その無線機をできるだけ多くのルーターから信号を受信できる中央の位置に設置します。無線機が動かないように固定します。オブザーバー無線機は、可能であれば天井または壁面の高い位置に設置してください。
ルーターのチャネル番号を確認します。チャネル番号は、電話機で Wi-Fi® アナライザー アプリを使用して確認できます。
"
rfFingerprintingRouterDataCollection(channel)
" を実行してデータ収集を開始します。channel は Wi-Fi のチャネル番号です。"max(abs(LLTF))" の値を監視します。1.2 よりも大きいか 0.01 よりも小さい場合は、関数
rfFingerprintingRouterDataCollection
の GAIN の入力を使用して受信機のゲインを調整します。
未知のルーターのデータの収集には補助関数 rfFingerprintingUnknownClassDataCollectionTx
および rfFingerprintingUnknownClassDataCollectionRx
を使用します。これらの関数は、L-LTF 信号を送受信する 2 台の ADALM-PLUTO 無線機を設定します。受信した信号と既知のルーターの信号の組み合わせでニューラル ネットワークの学習が行われます。2 台の ADALM-PLUTO 無線機が必要であり、2 台の別々の PC に接続することが推奨されます。次の手順に従います。
ADALM-PLUTO 無線機を未知のルーターとして動作する固定の PC に接続します。
"
rfFingerprintingUnknownClassDataCollectionTx
" を実行して送信を開始します。もう 1 台の ADALM-PLUTO 無線機をオブザーバーとして機能するモバイル PC に接続します。
"
rfFingerprintingUnknownClassDataCollectionRx
" を実行してデータ収集を開始します。この関数は、既定では各位置で 200 フレームずつ収集します。各位置が別々の未知のルーターを表します。新しい位置に移動するように関数から指示されたら、オブザーバー無線機を新しい位置に移動します。既定では、この関数は 10 か所からデータを収集します。
オブザーバーがビーコンをまったく受信しないかほとんど受信しない場合、オブザーバーを送信機の近くに移動します。
データ収集が完了したら、送信元無線機の MATLAB® セッションで "
release(sdrTransmitter)
" を呼び出します。
参考文献
[1] K. Sankhe, M. Belgiovine, F. Zhou, S. Riyaz, S. Ioannidis and K. Chowdhury, "ORACLE: Optimized Radio clAssification through Convolutional neuraL nEtworks," IEEE INFOCOM 2019 - IEEE Conference on Computer Communications, Paris, France, 2019, pp. 370-378.
参考
トピック
- MATLAB による深層学習 (Deep Learning Toolbox)