?
Solved

Impersonation & Cloaking

Posted on 2003-03-13
14
Medium Priority
?
484 Views
Last Modified: 2008-02-20
I am looking for a very simple set of example code that uses impersonation cloaking.

1) A server app that listens on a tcp/ip port. When it receives a request from a client it will authenticate that client and then impersonate the client by trying to read a file using the client's credentials. If it can read the file it returns "yes" or some equivalent. If it can't it returns "no" or some equivalent.

2) A client app that will send requests to the server app defined above.

Both can be very basic and command-line based.
I just want a working example that illustrates the techniques involved.
0
Comment
Question by:ozymandias
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
14 Comments
 
LVL 5

Expert Comment

by:Kocil
ID: 8128412
Beg you pardon, this is a new terminology for me:
  impersonation cloaking.
  impersonate the client
  client's credentials

What the **** is that ?
0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 8128428

It certainly appears that you're looking for help building hacker tools.  Before anyone offers any help I hope that they'll insist that you demonstrate a legitimate use.


Kdo
0
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 8128435
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 15

Author Comment

by:ozymandias
ID: 8128612
This is nothing to do with hacker tools.

I want to create a server application that will authenticate a client using the native security provider on Windows2000.

Basically, I have some files that contain data and the data in the files can only be read by my data engine. My data engine acts as a server and listens on a tcp/ip port for a client request.

When it gets a client request, it authenticates the client and then attaches the clients credentials to a thread which will be used to read the data files. If the user does not have permission to read the files then the thread will not be able to read the files.

This method of getting a thread/process to use a process token that has a client's credentials attached is called impersonation. IN COM and COM+ you can set different impersonation levels and then use cloaking to impersonate a client when accessing resources.

I don't have any experiewnce of doing this but I am familiar with the concepts involved so I want tome example code to start with.
0
 
LVL 15

Author Comment

by:ozymandias
ID: 8128623
jkr...thanks for the pointer to the ms examples.
I will dowload the file (130MB !) and have a look.

500 points +more + A grade still open to anyone who can provide me with working exmaples of the code detailed in my original post.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8133000
I use MFC to save time messing with user interface and to use CString.  The core logic will be obvious and usefule even if you have an aversion to MFC.

Here's the client.  Just ctrate a new dialog-based app and add a button and put all of this in the OnButton1 code:
#include <afxsock.h>

void CDlgSockClientDlg::OnButton1()
{
     AfxSocketInit();   // put this eleshwere ... just call it once

     CString sSocketIP= "127.0.0.1";
     CString sPortNum=  "12345";
     DWORD nLastErr= 0;

     int nPortNum=  atoi( sPortNum );

     CSocket cSocket;

     BOOL fRet= cSocket.Create();
     if ( fRet == 0 ) {
          MessageBox( "Unable to create socket" );
          nLastErr= GetLastError();  // TBD: display err code
          return;
     }

     fRet= cSocket.Connect( sSocketIP, nPortNum );
     if ( fRet == 0 ) {
          MessageBox( "Unable to connect to host" );
          nLastErr= GetLastError();  // TBD: display err code
          return;
     }
:

   CString sPkt;
   CString sPayload= "username:password@.";  
   sPkt.Format("DR%04d%s", sPayload.GetLength(), sPayload );

     CSocketFile file( &cSocket );
     try {
          CArchive    arOut(&file, CArchive::store | CArchive::bNoFlushOnDelete ); // noDelete prevents the outer exception
          arOut.Write( (LPCSTR)sPkt, sPkt.GetLength() );
          arOut.Flush();
     }
     catch( CException* pEx ) {
          MessageBox( "Error writing to socket" );
          pEx->Delete();
          return;
     }
     MessageBox( "successfully sent packet" );
     
     CArchive    arIn( &file, CArchive::load);
     
     int nActual;
     char buf[100];
     CString sResponse;

     try {
          nActual= arIn.Read( buf, 6 ); // get hdr
     }
     catch(...) {
          MessageBox( "Error reading from socket" );
          return;
     }
     if ( nActual != 6 ) {
          sResponse=  "Error! short packet: ";
          sResponse+= CString( buf, nActual );
          MessageBox( sResponse );
          return;
     }
     CString sTmp= CString( &buf[2], 4 );
     int nDataLen= atoi( sTmp );
     // LogPrintf( "Pkt Hdr: Len= %d", (int) nAceMsgLen );

     //----------------------------------------------- read the rest of the msg
     nActual= arIn.Read( buf, nDataLen );  
     buf[nDataLen]= 0;
     MessageBox( buf,"response from host" );

}
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8133004
host coming...
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8133204
I created the host from an existing host simulator.  It is also a simple dialog-based MFC app.  It is slightly more comples, in that there si a multi-line edit box used to display a log of actions.  Just draw an edit box, giving it a n ID of IDED_Log.  Use the Classwizard to associate it with a Control variable, m_ctlEditLog.  You'll end up with this in the DoDataExchange

      DDX_Control(pDX, IDED_Log, m_ctlEditLog);

I added this near the top:

//----------- a slight embellishemt to CSocket calls my local fn to hand incomming
class CListen : public CSocket {
public:
      CListen() {};
      virtual ~CListen() {};
public:
      virtual void OnAccept(int nErrorCode);
protected:
};
void CListen::OnAccept(int nErrorCode)
{
      AddToLog("On Accept" );
      CSocket::OnAccept(nErrorCode);
      gpDlg->DoOnAccept();
}

CListen*     gpSocket;
CDlgSockDlg* gpDlg;
BOOL         TextFileToStr( LPCSTR sFilename, CString& s );

//---------------------------- message logging
void AddToLog( LPCSTR s ) { gpDlg->AddToLog(s); }
void AddToLog( LPCSTR s, DWORD n ) {
      CString sTmp; sTmp.Format("%s : %x", s, n );
      AddToLog( sTmp );
}
=-=--==-=-=--==-=-=-=-=-=-=-=-=-=-=-=-=-
I added a [Start Listening] button with this handler:

void CDlgSockDlg::OnPbListen()
{
      CString sMsg;
      UpdateData( TRUE ); // get portnum
      gpSocket= new CListen();

      if ( ! gpSocket ) {
            AfxMessageBox ( "Unable to allocate memory for listener socket!" ) ;
            return;
      }
      if ( ! gpSocket->Create ( m_nPortNum ) ) {
            DWORD dwErr = gpSocket->GetLastError() ;
            switch ( dwErr ) {
                  case WSAEADDRINUSE:  // example of expected error handler
                        AfxMessageBox ( "The WWW port is already in use!" ) ;
                  break ;
            default:  // example of generic error handler
                  AfxMessageBox ( "Listener socket Create failed: %x", dwErr ) ;
            }
            return;
      }
      BOOL fRet = gpSocket->Listen() ;
      if ( ! fRet ) {
            DWORD dwErr = gpSocket->GetLastError() ;
            sMsg.Format ( "Listener socket Listen failed: %x\n", dwErr );
            AfxMessageBox ( sMsg ) ;
      }
      sMsg.Format("Listening on port: %d", m_nPortNum );
      AddToLog( sMsg );
}
=-=--==-=-=--==-=-=-=-=-=-=-=-=-=-=-=-=-
Here's the code that interprets the data coming from the client:

//-------------------------------------- client is pressing our buttons
// look for a 2-letter signature, a 4-digit packet length, then the user:password@domain
//
void CDlgSockDlg::DoOnAccept()
{
      CString sMsg;
      CString sHdr, sData;
      int     nRespLen;
      char    buf[400];          
      
      AddToLog("Connection requested");

      CSocket sockRecv;
      gpSocket->Accept( sockRecv );

      CSocketFile file( &sockRecv );
      CArchive    arIn( &file, CArchive::load);
      CArchive   arOut( &file, CArchive::store);

      int nActual= arIn.Read( buf, 6 ); // length for subsequent response data (not including this)

      if ( nActual != 6 ) {
            AddToLog("Rx: Unexpected/Invalid packet" );
            return;
      }
      sHdr= CString( buf, 6 );
      if ( sHdr.Left(2) != "DR" ) {
            AddToLog("Rx: Unexpected/Invalid packet" );
      }
      nRespLen= atoi( sHdr.Mid(2) );

      sMsg.Format( "Data Pkt: Len= %d ", nRespLen );
      AddToLog( sMsg );

      //----- read the packet data "username:password"
      nActual= arIn.Read( buf, nRespLen );  
      sData= CString( buf, nRespLen );

      sMsg.Format("Rx: Data: '%s'", (LPCSTR)sData );
      AddToLog( sMsg );

      int nOffset= sData.Find(":");
      if (nOffset == -1 ) {
            AddToLog("Rx: Yukky (malformed) data in packet" );
            return;
      }

      //------------------------------- take the nibey shot
      CString sUser=   sData.Left( nOffset);
      CString sPswd=   sData.Mid( nOffset+1);
      CString sDomain= "";
      nOffset= sPswd.Find("@");
      if ( nOffset != -1 ) {
            sDomain= sPswd.Mid( nOffset+1 );
            sPswd = sPswd.Left( nOffset );
      }

      bool fRet= VerifyCredentials( sUser, sPswd, sDomain );

      //------------------------------- respond to the request
      CString sPacket=   "DR0003";
      sPacket += fRet ? "yes" : "no ";

      arOut.Write( (LPCSTR)sPacket, sPacket.GetLength() );  
      arOut.Flush();

      sMsg.Format("Wrote %d Bytes of data: %s...", sPacket.GetLength(), (LPCSTR)sPacket );
      AddToLog( sMsg );
      
      return;
}

=-=-=-=-=-=-=-=-=-=-=-=-
Conttinued...
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8133224
Heres' the code that validates the credentials:

#define CSTR_TestFileName "c:\\temp\\test.txt"

bool VerifyCredentials( LPCSTR sUser, LPCSTR sPswd, LPCSTR sDomain )
{
     HANDLE hToken;
     if (sDomain == "" ) {
          sDomain= 0;
     }
     BOOL fRet= ::LogonUser( (char*)sUser,(char*)sDomain,(char*)sPswd,
          LOGON32_LOGON_BATCH,
          LOGON32_PROVIDER_DEFAULT,
          &hToken
     );
     if ( !fRet) {
          AddToLog("Unable to logon with user/pswd/domain credentials",GetLastError() );
          DWORD dwErr= GetLastError();
          return( false );
     }

     fRet= ::ImpersonateLoggedOnUser( hToken );
     if ( !fRet) {
          AddToLog("ImpersonateLoggedOnUser() failed",GetLastError() );
          return( false );
     }

     CFile cf;
     fRet= cf.Open( CSTR_TestFileName, CFile::modeReadWrite );
     if ( !fRet ) {
          AddToLog( "OpenFile failed",GetLastError() );
          ::RevertToSelf();
          return( false );
     }
     //---------------------- unnecessary read test to satisfy the spec
     char buf[10];
     int nActual= cf.Read( buf, 10 );
     if (nActual != 10 ) {
          AddToLog( "Read File failed",GetLastError() );
          ::RevertToSelf();
          cf.Close();
          return( false );
     }

     return( true );
}

=-=-=-=-=-=-=-=-=-=-=-=-=-
And there you habe it!

In all socket operations, I always send and recieve packets.  Here I used a 2-letter signature, followed by a four-digit length (all in text).  That way, I always know exactly how many bytes to expect and I don't need to hang around for a time out.  

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8133268
oops, here's something missing:
void CDlgSockDlg::AddToLog( LPCSTR s )
{
     m_ctlEditLog.SetSel(-1,-1);
     m_ctlEditLog.ReplaceSel(s);
     m_ctlEditLog.ReplaceSel("\r\n" );
}

And a hnddy utility (not used in the program, consider ti a bonus :)

//-------------------------------
// read an entire text file into a string
//
BOOL TextFileToStr( LPCSTR sFilename, CString& s )
{
     char sBuf[513];
     HFILE hFile= _lopen(sFilename, OF_READ );

     if (hFile == HFILE_ERROR ) {
          return( FALSE );
     }
     int nFileLen= _llseek( hFile, 0L, SEEK_END );
     _llseek( hFile, 0L, SEEK_SET );
     for (int j=0; j<nFileLen; j += 512) {
          int nActual= _lread( hFile, sBuf, 512 );
          sBuf[nActual]= 0;
          s += sBuf;
     }
     _lclose( hFile );
     //s.Replace("\r",NULL);    
     return( TRUE );
}
0
 
LVL 15

Author Comment

by:ozymandias
ID: 8134745
wow dan...you've been busy.

Thanks.

I'll have a look at all that and get back to you.
0
 
LVL 15

Author Comment

by:ozymandias
ID: 8134919
Hi, Dan.
Please forgive my ignorance but from reading your code it looks like "username:password@domain" is passed in plain text to the server.

a) This is not a good idea
b) it requires the user of the client to enter this information.

I should have made this clearer but I wanted the client to pass the credentials (token) of the user currently logged on the workstation.

Anyway, from the code in AuthSocket provided by jkr courtesy of MSDN and the stuff you've posted I think I have enough to be going on with.

I will award points to jkr and post extra points for Dan in this topic area.

Cheers.
0
 
LVL 15

Author Comment

by:ozymandias
ID: 8134922
Thanks again.
0
 
LVL 15

Author Comment

by:ozymandias
ID: 8134925
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question