メインコンテンツ

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 無線機です。既知のルーターのデータは次のようにして収集しました。

  1. ルーターで使用される WLAN チャネルに基づいてオブザーバーの中心周波数を設定

  2. ビーコン フレームを受信

  3. L-LTF 信号を抽出

  4. MAC アドレスを復号化してラベルとして使用

  5. L-LTF 信号をそのラベルと共に保存

  6. 手順 2 ~ 5 を繰り返して numKnownRouters のルーターから numFramesPerRouter フレームを収集

未知のルーターのビーコン フレームのシミュレーションでは、移動する ADALM-PLUTO 無線機を送信機として使用しています。この無線機からランダムな MAC アドレスでビーコン フレームを繰り返し送信します。未知のルーターのデータは次のようにして収集しました。

  1. ランダムな MAC アドレスでビーコン フレームを生成

  2. ADALM-PLUTO 無線機を使用したビーコン フレームの繰り返し送信を開始

  3. NUMFRAMES のビーコン フレームを収集

  4. L-LTF 信号を抽出

  5. L-LTF フレームをラベル "Unknown" で保存

  6. 無線機を別の位置に移動

  7. 手順 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';

Figure contains an object of type ConfusionMatrixChart. The chart of type ConfusionMatrixChart has title Confusion Matrix for Test Data.

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 指紋のニューラル ネットワークの学習を行います。この方法は、ルーターとそのアンテナが固定されていて、意図せずに動くことはほとんどない場合に特に効果的です。たとえば、ほとんどのオフィス環境では、ルーターは天井に取り付けられています。次の手順に従います。

  1. ADALM-PLUTO 無線機をオブザーバー無線機として使用する PC に接続します。

  2. その無線機をできるだけ多くのルーターから信号を受信できる中央の位置に設置します。無線機が動かないように固定します。オブザーバー無線機は、可能であれば天井または壁面の高い位置に設置してください。

  3. ルーターのチャネル番号を確認します。チャネル番号は、電話機で Wi-Fi® アナライザー アプリを使用して確認できます。

  4. "rfFingerprintingRouterDataCollection(channel)" を実行してデータ収集を開始します。channel は Wi-Fi のチャネル番号です。

  5. "max(abs(LLTF))" の値を監視します。1.2 よりも大きいか 0.01 よりも小さい場合は、関数 rfFingerprintingRouterDataCollection の GAIN の入力を使用して受信機のゲインを調整します。

未知のルーターのデータの収集には補助関数 rfFingerprintingUnknownClassDataCollectionTx および rfFingerprintingUnknownClassDataCollectionRx を使用します。これらの関数は、L-LTF 信号を送受信する 2 台の ADALM-PLUTO 無線機を設定します。受信した信号と既知のルーターの信号の組み合わせでニューラル ネットワークの学習が行われます。2 台の ADALM-PLUTO 無線機が必要であり、2 台の別々の PC に接続することが推奨されます。次の手順に従います。

  1. ADALM-PLUTO 無線機を未知のルーターとして動作する固定の PC に接続します。

  2. "rfFingerprintingUnknownClassDataCollectionTx" を実行して送信を開始します。

  3. もう 1 台の ADALM-PLUTO 無線機をオブザーバーとして機能するモバイル PC に接続します。

  4. "rfFingerprintingUnknownClassDataCollectionRx" を実行してデータ収集を開始します。この関数は、既定では各位置で 200 フレームずつ収集します。各位置が別々の未知のルーターを表します。

  5. 新しい位置に移動するように関数から指示されたら、オブザーバー無線機を新しい位置に移動します。既定では、この関数は 10 か所からデータを収集します。

  6. オブザーバーがビーコンをまったく受信しないかほとんど受信しない場合、オブザーバーを送信機の近くに移動します。

  7. データ収集が完了したら、送信元無線機の 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.

参考

トピック