Tuesday, May 7, 2013

Websense app replacement for stealth mode


    Nontrivial task for Security administrator can be reading data from client, or troubleshooting scenario, when a company policies dictates to use Endpoint in Stealth mode. Switching to UI mode from previous example has been prohibited as well.

   From first point parsing files such as XML config, sqlite format dbs is good idea but this case has couple disadvantages (for instance – yeah, we able to get Primary and Secondary servers, but who is an active at this moment, etc...)

   So, looks like we need our personal application to gather all necessary data. 


Let's start our investigation from observing processes in memory. WinSpy++ is a nice tool for that. Drag Finder Aim and drop on Endpoint client window (for investigation purposes we are using UI mode – temporary).

   Have a look at Windows tab, interesting. Almost all data is available just from static labels.



    Knowing proper handlers we can pull up necessary info to our app. OK, how about buttons? Very simple too, knowing a button handler we can send proper event, for example mouse button click. Main window handler can be detected from memory window caption 'Websense Endpoint' scanning.
    My final result you can check from pictures posted bellow:




    Unfortunately I don't have any C licenses, so I was using Lazarus Free Pascal.

    For button click emulation I was using two types of events somehow, different buttons were reacting differently. As a parameter I'm sending necessary button handler and type of clicking.


Procedure SendButtonClick(TypeClick:Boolean; myhandle:Thandle);
Begin
  ShowWindow(WebsenseHandle,10);
  ShowWindow(WebsenseHandle,SW_HIDE);
  If Typeclick=True then
     begin
     SendMessage(myhandle, WM_LBUTTONDOWN,0,0);
     SendMessage(myhandle, WM_LBUTTONUP,0,0);
     End
  else
     PostMessage(myhandle, BM_CLICK, 0, 0);

End; 

    Our memory hound function, with 'Websense Endpoint' input string and main window handler return as a result.

 function FindWindowExtd(partialTitle: string): HWND;
var
  hWndTemp: hWnd;
  iLenText: Integer;
  cTitletemp: array [0..254] of Char;
  sTitleTemp: string;
begin
  hWndTemp := FindWindow(nil, nil);
  while hWndTemp <> 0 do begin
    iLenText := GetWindowText(hWndTemp, cTitletemp, 255);
    sTitleTemp := cTitletemp;
    sTitleTemp := UpperCase(copy( sTitleTemp, 1, iLenText));
    partialTitle := UpperCase(partialTitle);
    if pos( partialTitle, sTitleTemp ) <> 0 then
      Break;
    hWndTemp := GetWindow(hWndTemp, GW_HWNDNEXT);
  end;

  result := hWndTemp;

end; 

Next procedure is building tree list view of all child objects from main endpoint window.

procedure Sys_Websense_Tree(Node: TTreeNode; AHandle: HWND);
const
  MAX = 128;
var
  szClassName, szCaption: array[0..MAX - 1] of Char;
  Result    : String;
  szFileName : array[0..255] of Char;
  PID, TID: Cardinal;
  szLayoutName: array[0..MAX - 1] of Char;

begin

  while AHandle <> 0 do
  begin

    GetClassName(AHandle, szClassName, MAX);
    GetWindowText(AHandle, szCaption, MAX);
    FillChar(szFileName, 256, #0);
    TID := GetWindowThreadProcessId(AHandle, PID);

    AttachThreadInput(GetCurrentThreadId, TID, True);
    VerLanguageName(GetKeyboardLayout(TID) and $FFFF, szLayoutName, MAX);
    AttachThreadInput(GetCurrentThreadId, TID, False);

    Result := Format('%s [%s] Caption = %s, Handle = %d',
     [String(szClassName), String(szFileName), String(szCaption), AHandle]);



    If (Ahandle = WebsenseHandle) or (GetParent (Ahandle)=WebsenseHandle) then begin
      MainSenseStatusForm.LL:=MainSenseStatusForm.LL+1;
      With Vault[MainSenseStatusForm.LL-1] do begin
       ObjectType:=String(szClassName);
        FileObject:=String(szFileName);
        Caption:=String(szCaption);
        Handle:= Ahandle;
        ePid:=PID;
        Layout:=String(szLayoutName);
      end;
      result:=inttostr(MainSenseStatusForm.LL-1)+'. '+result;
      Sys_Websense_Tree(LogForm.TreeView1.Items.Add(Node,Result),
      GetWindow(AHandle, GW_CHILD));

    end;

    AHandle := GetNextWindow(AHandle, GW_HWNDNEXT);
  end;
end; 
Then all working set moving to array of elements, Vault.

  CardOfObject = record
    ObjectType: String;
    FileObject: String;
    Caption:String;
    Handle: Thandle;
    ePID: Cardinal;
    Layout: String
   end; 
Vault: array of CardOfObject;
And key procedure for application, presenting info.

procedure TMainSenseStatusForm.RefreshButtonClick(Sender: TObject);
var
  StartHandle: Thandle;
begin

  PreInit(LL);

  StartHandle := GetDeskTopWindow;
  WebsenseHandle :=  FindWindowExtd('Websense Endpoint');
  Sys_Websense_Tree(nil, WebsenseHandle);
  if vault[9].Caption<>'' then UserNameLabeledEdit.text:=Vault[9].Caption;
  if vault[12].Caption<>''then DataSecurityLabeledEdit.text:=Vault[12].Caption;
  if vault[14].Caption<>''then UpdatedLabeledEdit.text:=Vault[14].Caption;
  if vault[18].Caption<>''then ProfileLabeledEdit.text:=Vault[18].Caption;

  if Vault[55].Caption='Disconnected' then

     begin
          ConnectionStatusLabel.Caption:='Disconnected';
          ConnectionStatusLabel.color:=clRed;
     end;
  if Vault[55].Caption='Connected' then
     begin
          ConnectionStatusLabel.Caption:='Connected';
          ConnectionStatusLabel.color:=clGreen;
     end;

   if Vault[20].Caption='Enabled' then

     begin
          EndpointStatusLabel.Caption:='Enabled';
          EndpointStatusLabel.Color:=clGreen;
     end;
   if Vault[20].Caption='Disabled' then
     begin
          EndpointStatusLabel.Caption:='Disabled';
          EndpointStatusLabel.Color:=clRed;
     end;
end;
As an example to check Policy, Fingerprint, Profile versions, I'm using next procedure.

procedure TMainSenseStatusForm.VersionsButtonClick(Sender: TObject);
begin
  SendButtonClick(True, Vault[14].Handle);
end;



PS: Final question for today. How many times did you click red cross button trying closing picture window? :)
And if you want to try this app just let me know.



No comments:

Post a Comment