Wo ist der Sicherheitsfehler im Quellcode?

Heute Abend hatte ich im Rahmen der Security09 des e-center eine interessante Diskussion. Sind Open Source Produkte per se sicherer als Closed Source Produkte?

Die Idee ist ja folgende:

  1. Bei Closed Source Produkten haben in der Theorie nur einige wenige Entwickler Zugriff auf den Quellcode.
  2. Bei Open Source Produkten haben in der Theorie viele Entwickler Zugriff auf den Quellcode.
  3. Und wenn viele Leute sich dann den Quellcode ansehen, dann würden sie alle Fehler finden, und diese auch ausbessern.

Nun gut. Soweit die Theorie.

In der Praxis schaut es dann doch ein bisschen anders aus.

Zum Ersten gibt es auch bei sogenannten Closed Source Produkten oft die Möglichkeit sich den Quellcode anzusehen. Bei Microsoft ist das das Shared Source Programm, und bietet seit Jahren Zugriff auf den Quellcode von zum Beispiel Microsoft Windows und Microsoft Office.

Zum Zweiten ist die vielbeschworene Community oft gar nicht so groß, wie man im allgemeinen gerne annimmt. Da kann es dann schon mal sein, dass auch bei weltbekannten Projekten nur zwei Handvoll Mitarbeiter wirklich aktiv dran sind.

Zum Dritten sind Sicherheitsfehler im Quellcode oft gar nicht so einfach zu finden.

Oder doch? Kleiner Test gefällig? O.K. Wo ist hier der Fehler:

 #define Smb2GetWorkItem( WI ) ((PSMB2_WORK_ITEM)(WI->ProviderWorkItem))
 ...
 typedef struct _SRV_WORK_ITEM
 {
 ...
     //
     // This is the Receive Buffer for the incoming request
     //
     PSRVBUFFER ReceiveBuffer;
     PSRVBUFFER ResponseBuffer;
  
 ...
 } SRV_WORK_ITEM, *PSRV_WORK_ITEM;
  
 ...
 NTSTATUS
 Smb2ValidateProviderCallback( PSRV_WORK_ITEM WorkItem )
 {
     PSMB2_HEADER pHeader = (PSMB2_HEADER)WorkItem->ReceiveBuffer->Buffer;
     PSMB2_WORK_ITEM pWI = Smb2GetWorkItem( WorkItem );
     PSMB2_CONNECTION pC = Smb2GetConnection( WorkItem->Connection );
     NTSTATUS status;
  
     pWI->ParentWorkItem = WorkItem;
     pWI->AsyncId = RFSTABLE64_INVALID_ITEM;
     WorkItem->ProviderWorkItemCleanupRoutine = Smb2CleanupWorkItem;
  
 ...
  
     if( pHeader->ProtocolId != SMB2_PROTOCOL_ID )
     {
         if( pHeader->ProtocolId == SMB_PROTOCOL_ID &&
             pC->Dialect == 0xFFFF )
         {
             //
             // Handle downlevel multi-negotiate
             //
             pWI->Command = SMB2_0_COMMAND_NEGOTIATE;
             goto process_packet;
         }
         else
         {
             WorkItem->DisconnectConnection = TRUE;
             return STATUS_INVALID_PARAMETER;
         }
     }
  
     pWI->Command = pHeader->Command;
  
  
 ...
  
 process_packet:
     if( SRVWPP_LOG_MESSAGE( DEBUG_MODULE_SRV2, DEBUG_PERF ) )
     {
         Smb2OutputWorkItemRequest( WorkItem );
     }
  
     if( ValidateRoutines[pHeader->Command ] == NULL )
     {
         return Smb2ValidateNotImplemented( WorkItem );
     }
     else
     {
         return (ValidateRoutines[pHeader->Command])( WorkItem );
     }
 }

 

Wer den Fehler findet, darf ihn auch behalten. :-)

Im Ernst: Wer hätte den Fehler gefunden? Ehrlich!

Die Conclusio:

  • Programmieren kann bald mal wer.
  • Gut Programmieren erfordert dann schon einiges an Ausbildung und Erfahrung
  • Sicher Programmieren erfordert Regeln und Prozesse, sowie entsprechende Spezialkenntnisse. Viele Augenpaare alleine sind da auch keine wirkliche Hilfe.

PS: Das war gerade Quellcode aus dem Windows 7 Release Candidate.

In der finalen Version von Windows 7 ist dieser Fehler schon behoben und entfernt. Gefunden wurde der Fehler schlussendlich durch sogenanntes Fuzzing, also das bewusste Verwenden von fehlerhaften Netzwerkpaketen, um eventuelle Fehler in der Software zu entdecken. Was ja dann auch prompt gelang.

PPS: Wer mir glaubhaft versichern kann den Fehler im obigen Quellcode alleine gefunden zu haben, bekommt von mir ein “Writing Secure Code” Buch von Michael Howard.

Obwohl: Wer den Fehler selber findet, braucht das Buch wahrscheinlich gar nicht mehr :-)