| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9cc89f5 commit 0b631bb
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -415,6 +415,13 @@ const win32 = { | |||
| 415 | 415 | // We matched a device root (e.g. \\\\.\\PHYSICALDRIVE0) | |
| 416 | 416 | device = `\\\\${firstPart}`; | |
| 417 | 417 | rootEnd = 4; | |
| 418 | + const colonIndex = StringPrototypeIndexOf(path, ':'); | ||
| 419 | + // Special case: handle \\?\COM1: or similar reserved device paths | ||
| 420 | + const possibleDevice = StringPrototypeSlice(path, 4, colonIndex + 1); | ||
| 421 | + if (isWindowsReservedName(possibleDevice, possibleDevice.length - 1)) { | ||
| 422 | + device = `\\\\?\\${possibleDevice}`; | ||
| 423 | + rootEnd = 4 + possibleDevice.length; | ||
| 424 | + } | ||
| 418 | 425 | } else if (j === len) { | |
| 419 | 426 | // We matched a UNC root only | |
| 420 | 427 | // Return the normalized version of the UNC root since there | |
@@ -573,6 +580,36 @@ const win32 = { | |||
| 573 | 580 | joined = `\\${StringPrototypeSlice(joined, slashCount)}`; | |
| 574 | 581 | } | |
| 575 | 582 | ||
| 583 | + // Skip normalization when reserved device names are present | ||
| 584 | + const parts = []; | ||
| 585 | + let part = ''; | ||
| 586 | + | ||
| 587 | + for (let i = 0; i < joined.length; i++) { | ||
| 588 | + if (joined[i] === '\\') { | ||
| 589 | + if (part) parts.push(part); | ||
| 590 | + part = ''; | ||
| 591 | + // Skip consecutive backslashes | ||
| 592 | + while (i + 1 < joined.length && joined[i + 1] === '\\') i++; | ||
| 593 | + } else { | ||
| 594 | + part += joined[i]; | ||
| 595 | + } | ||
| 596 | + } | ||
| 597 | + // Add the final part if any | ||
| 598 | + if (part) parts.push(part); | ||
| 599 | + | ||
| 600 | + // Check if any part has a Windows reserved name | ||
| 601 | + if (parts.some((p) => { | ||
| 602 | + const colonIndex = StringPrototypeIndexOf(p, ':'); | ||
| 603 | + return colonIndex !== -1 && isWindowsReservedName(p, colonIndex); | ||
| 604 | + })) { | ||
| 605 | + // Replace forward slashes with backslashes | ||
| 606 | + let result = ''; | ||
| 607 | + for (let i = 0; i < joined.length; i++) { | ||
| 608 | + result += joined[i] === '/' ? '\\' : joined[i]; | ||
| 609 | + } | ||
| 610 | + return result; | ||
| 611 | + } | ||
| 612 | + | ||
| 576 | 613 | return win32.normalize(joined); | |
| 577 | 614 | }, | |
| 578 | 615 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -110,6 +110,14 @@ joinTests.push([ | |||
| 110 | 110 | [['c:.', 'file'], 'c:file'], | |
| 111 | 111 | [['c:', '/'], 'c:\\'], | |
| 112 | 112 | [['c:', 'file'], 'c:\\file'], | |
| 113 | + // UNC path join tests (Windows) | ||
| 114 | + [['\\server\\share', 'file.txt'], '\\server\\share\\file.txt'], | ||
| 115 | + [['\\server\\share', 'folder', 'another.txt'], '\\server\\share\\folder\\another.txt'], | ||
| 116 | + [['\\server\\share', 'COM1:'], '\\server\\share\\COM1:'], | ||
| 117 | + [['\\server\\share', 'path', 'LPT1:'], '\\server\\share\\path\\LPT1:'], | ||
| 118 | + [['\\fileserver\\public\\uploads', 'CON:..\\..\\..\\private\\db.conf'], | ||
| 119 | + '\\fileserver\\public\\uploads\\CON:..\\..\\..\\private\\db.conf'], | ||
| 120 | + | ||
| 113 | 121 | // Path traversal in previous versions of Node.js. | |
| 114 | 122 | [['./upload', '/../C:/Windows'], '.\\C:\\Windows'], | |
| 115 | 123 | [['upload', '../', 'C:foo'], '.\\C:foo'], | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,19 @@ if (!common.isWindows) { | |||
| 9 | 9 | } | |
| 10 | 10 | ||
| 11 | 11 | const normalizeDeviceNameTests = [ | |
| 12 | + // UNC paths: \\server\share\... is a Windows UNC path, where 'server' is the network server name and 'share' | ||
| 13 | + // is the shared folder. These are used for network file access and are subject to reserved device name | ||
| 14 | + // checks after the share. | ||
| 15 | + { input: '\\\\server\\share\\COM1:', expected: '\\\\server\\share\\COM1:' }, | ||
| 16 | + { input: '\\\\server\\share\\PRN:', expected: '\\\\server\\share\\PRN:' }, | ||
| 17 | + { input: '\\\\server\\share\\AUX:', expected: '\\\\server\\share\\AUX:' }, | ||
| 18 | + { input: '\\\\server\\share\\LPT1:', expected: '\\\\server\\share\\LPT1:' }, | ||
| 19 | + { input: '\\\\server\\share\\COM1:\\foo\\bar', expected: '\\\\server\\share\\COM1:\\foo\\bar' }, | ||
| 20 | + { input: '\\\\server\\share\\path\\COM1:', expected: '\\\\server\\share\\path\\COM1:' }, | ||
| 21 | + { input: '\\\\server\\share\\COM1:..\\..\\..\\..\\Windows', expected: '\\\\server\\share\\Windows' }, | ||
| 22 | + { input: '\\\\server\\share\\path\\to\\LPT9:..\\..\\..\\..\\..\\..\\..\\..\\..\\file.txt', | ||
| 23 | + expected: '\\\\server\\share\\file.txt' }, | ||
| 24 | + | ||
| 12 | 25 | { input: 'CON', expected: 'CON' }, | |
| 13 | 26 | { input: 'con', expected: 'con' }, | |
| 14 | 27 | { input: 'CON:', expected: '.\\CON:.' }, | |
@@ -81,6 +94,8 @@ const normalizeDeviceNameTests = [ | |||
| 81 | 94 | // Test cases from original vulnerability reports or similar scenarios | |
| 82 | 95 | { input: 'COM1:.\\..\\..\\foo.js', expected: '.\\COM1:..\\..\\foo.js' }, | |
| 83 | 96 | { input: 'LPT1:.\\..\\..\\another.txt', expected: '.\\LPT1:..\\..\\another.txt' }, | |
| 97 | + // UNC paths | ||
| 98 | + { input: '\\\\?\\COM1:.\\..\\..\\foo2.js', expected: '\\\\?\\COM1:\\foo2.js' }, | ||
| 84 | 99 | ||
| 85 | 100 | // Paths with device names not at the beginning | |
| 86 | 101 | { input: 'C:\\CON', expected: 'C:\\CON' }, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments