github.com/google/osv-scalibr@v0.4.1/detector/weakcredentials/winlocal/winlocal_windows_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build windows
    16  
    17  package winlocal
    18  
    19  import (
    20  	"slices"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  )
    25  
    26  func TestInternalScan(t *testing.T) {
    27  	tests := []struct {
    28  		name                       string
    29  		hashes                     []*userHashInfo
    30  		wantErr                    error
    31  		expectedFindingsReferences []string
    32  	}{
    33  		{
    34  			name: "no_hashes_returns_no_findings",
    35  			hashes: []*userHashInfo{
    36  				&userHashInfo{
    37  					lmHash: "",
    38  					ntHash: "",
    39  				},
    40  			},
    41  			expectedFindingsReferences: nil,
    42  		},
    43  		{
    44  			name: "lm_hash_returns_lm_finding",
    45  			hashes: []*userHashInfo{
    46  				&userHashInfo{
    47  					lmHash: "irrelevant",
    48  					ntHash: "irrelevant",
    49  				},
    50  			},
    51  			expectedFindingsReferences: []string{
    52  				vulnRefLMPassword,
    53  			},
    54  		},
    55  		{
    56  			name: "weak_password_returns_finding",
    57  			hashes: []*userHashInfo{
    58  				&userHashInfo{
    59  					lmHash: "",
    60  					ntHash: "329153F560EB329C0E1DEEA55E88A1E9", // root
    61  				},
    62  			},
    63  			expectedFindingsReferences: []string{
    64  				vulnRefWeakPass,
    65  			},
    66  		},
    67  		{
    68  			name: "weak_password_and_lm_hash_returns_findings",
    69  			hashes: []*userHashInfo{
    70  				&userHashInfo{
    71  					lmHash: "D480EA9533C500D4AAD3B435B51404EE", // root
    72  					ntHash: "329153F560EB329C0E1DEEA55E88A1E9", // root
    73  				},
    74  			},
    75  			expectedFindingsReferences: []string{
    76  				vulnRefLMPassword,
    77  				vulnRefWeakPass,
    78  			},
    79  		},
    80  	}
    81  
    82  	for _, tc := range tests {
    83  		t.Run(tc.name, func(t *testing.T) {
    84  			d := Detector{}
    85  			result, err := d.internalScan(t.Context(), tc.hashes)
    86  			if err != nil {
    87  				t.Fatalf("internalScan(...) unexpected error, got: %v, want: %v", err, tc.wantErr)
    88  			}
    89  
    90  			for _, finding := range result.GenericFindings {
    91  				if !slices.Contains(tc.expectedFindingsReferences, finding.Adv.ID.Reference) {
    92  					t.Errorf("internalScan(...) unexpected finding, got: %v, want: %v", finding.Adv.ID.Reference, tc.expectedFindingsReferences)
    93  				}
    94  			}
    95  		})
    96  	}
    97  }
    98  
    99  func TestBruteforce(t *testing.T) {
   100  	tests := []struct {
   101  		name    string
   102  		hashes  []*userHashInfo
   103  		wantMap map[string]string
   104  	}{
   105  		{
   106  			name: "no_hashes_returns_no_findings",
   107  			hashes: []*userHashInfo{
   108  				&userHashInfo{
   109  					username: "user",
   110  					lmHash:   "",
   111  					ntHash:   "",
   112  				},
   113  			},
   114  			wantMap: map[string]string{},
   115  		},
   116  		{
   117  			name: "lm_not_weak_returns_no_finding",
   118  			hashes: []*userHashInfo{
   119  				&userHashInfo{
   120  					username: "root",
   121  					lmHash:   "978A0A1C20E21F373757F7116254AD0B", // AVeryComplexPassword
   122  					ntHash:   "",
   123  				},
   124  			},
   125  			wantMap: map[string]string{},
   126  		},
   127  		{
   128  			name: "nt_weak_password_returns_finding",
   129  			hashes: []*userHashInfo{
   130  				&userHashInfo{
   131  					username: "root",
   132  					lmHash:   "",
   133  					ntHash:   "0CB6948805F797BF2A82807973B89537", // test
   134  				},
   135  			},
   136  			wantMap: map[string]string{
   137  				"root": "test",
   138  			},
   139  		},
   140  		{
   141  			name: "nt_not_weak_returns_no_finding",
   142  			hashes: []*userHashInfo{
   143  				&userHashInfo{
   144  					username: "root",
   145  					lmHash:   "",
   146  					ntHash:   "D5F234DB9AA96CEAC168598BB576C7A6", // AVeryComplexPassword
   147  				},
   148  			},
   149  			wantMap: map[string]string{},
   150  		},
   151  	}
   152  
   153  	for _, tc := range tests {
   154  		t.Run(tc.name, func(t *testing.T) {
   155  			d := Detector{}
   156  			gotMap, err := d.bruteforce(t.Context(), tc.hashes)
   157  			if err != nil {
   158  				t.Fatalf("bruteforce(...) unexpected error: %v", err)
   159  			}
   160  
   161  			if diff := cmp.Diff(gotMap, tc.wantMap); diff != "" {
   162  				t.Errorf("bruteforce(...) unexpected diff (-want +got): %v", diff)
   163  			}
   164  		})
   165  	}
   166  }