cyberchef 9.37.1 → 9.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -2
- package/Gruntfile.js +2 -1
- package/package.json +2 -2
- package/src/core/Utils.mjs +2 -2
- package/src/core/config/Categories.json +1 -0
- package/src/core/config/OperationConfig.json +106 -3
- package/src/core/config/modules/Default.mjs +2 -0
- package/src/core/lib/Binary.mjs +9 -5
- package/src/core/lib/Extract.mjs +16 -11
- package/src/core/lib/FileSignatures.mjs +12 -12
- package/src/core/lib/Protocol.mjs +47 -0
- package/src/core/lib/Sort.mjs +105 -0
- package/src/core/lib/Stream.mjs +22 -12
- package/src/core/operations/ExtractDates.mjs +7 -1
- package/src/core/operations/ExtractDomains.mjs +29 -5
- package/src/core/operations/ExtractEmailAddresses.mjs +29 -5
- package/src/core/operations/ExtractFilePaths.mjs +38 -14
- package/src/core/operations/ExtractIPAddresses.mjs +44 -27
- package/src/core/operations/ExtractMACAddresses.mjs +28 -6
- package/src/core/operations/ExtractURLs.mjs +28 -5
- package/src/core/operations/ParseTCP.mjs +245 -0
- package/src/core/operations/ParseUDP.mjs +29 -24
- package/src/core/operations/Sort.mjs +5 -105
- package/src/core/operations/Strings.mjs +36 -14
- package/src/core/operations/ToBase45.mjs +1 -1
- package/src/core/operations/Unique.mjs +25 -5
- package/src/core/operations/index.mjs +2 -0
- package/src/node/index.mjs +5 -0
- package/src/web/waiters/OperationsWaiter.mjs +5 -1
- package/tests/node/tests/operations.mjs +3 -4
- package/tests/operations/index.mjs +1 -0
- package/tests/operations/tests/ExtractEmailAddresses.mjs +4 -4
- package/tests/operations/tests/ParseTCP.mjs +44 -0
- package/tests/operations/tests/ParseUDP.mjs +5 -18
|
@@ -44,7 +44,13 @@ class ExtractDates extends Operation {
|
|
|
44
44
|
date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
|
|
45
45
|
regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
const results = search(input, regex);
|
|
48
|
+
|
|
49
|
+
if (displayTotal) {
|
|
50
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
51
|
+
} else {
|
|
52
|
+
return results.join("\n");
|
|
53
|
+
}
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
|
|
9
|
+
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Extract domains operation
|
|
@@ -25,9 +26,19 @@ class ExtractDomains extends Operation {
|
|
|
25
26
|
this.outputType = "string";
|
|
26
27
|
this.args = [
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
name: "Display total",
|
|
30
|
+
type: "boolean",
|
|
31
|
+
value: false
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "Sort",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
value: false
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "Unique",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
31
42
|
}
|
|
32
43
|
];
|
|
33
44
|
}
|
|
@@ -38,8 +49,21 @@ class ExtractDomains extends Operation {
|
|
|
38
49
|
* @returns {string}
|
|
39
50
|
*/
|
|
40
51
|
run(input, args) {
|
|
41
|
-
const displayTotal = args
|
|
42
|
-
|
|
52
|
+
const [displayTotal, sort, unique] = args;
|
|
53
|
+
|
|
54
|
+
const results = search(
|
|
55
|
+
input,
|
|
56
|
+
DOMAIN_REGEX,
|
|
57
|
+
null,
|
|
58
|
+
sort ? caseInsensitiveSort : null,
|
|
59
|
+
unique
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (displayTotal) {
|
|
63
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
64
|
+
} else {
|
|
65
|
+
return results.join("\n");
|
|
66
|
+
}
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import { search } from "../lib/Extract.mjs";
|
|
9
|
+
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Extract email addresses operation
|
|
@@ -25,9 +26,19 @@ class ExtractEmailAddresses extends Operation {
|
|
|
25
26
|
this.outputType = "string";
|
|
26
27
|
this.args = [
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
name: "Display total",
|
|
30
|
+
type: "boolean",
|
|
31
|
+
value: false
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "Sort",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
value: false
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "Unique",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
31
42
|
}
|
|
32
43
|
];
|
|
33
44
|
}
|
|
@@ -38,10 +49,23 @@ class ExtractEmailAddresses extends Operation {
|
|
|
38
49
|
* @returns {string}
|
|
39
50
|
*/
|
|
40
51
|
run(input, args) {
|
|
41
|
-
const displayTotal = args
|
|
52
|
+
const [displayTotal, sort, unique] = args,
|
|
42
53
|
// email regex from: https://www.regextester.com/98066
|
|
43
54
|
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
|
|
44
|
-
|
|
55
|
+
|
|
56
|
+
const results = search(
|
|
57
|
+
input,
|
|
58
|
+
regex,
|
|
59
|
+
null,
|
|
60
|
+
sort ? caseInsensitiveSort : null,
|
|
61
|
+
unique
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (displayTotal) {
|
|
65
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
66
|
+
} else {
|
|
67
|
+
return results.join("\n");
|
|
68
|
+
}
|
|
45
69
|
}
|
|
46
70
|
|
|
47
71
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import { search } from "../lib/Extract.mjs";
|
|
9
|
+
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Extract file paths operation
|
|
@@ -25,19 +26,29 @@ class ExtractFilePaths extends Operation {
|
|
|
25
26
|
this.outputType = "string";
|
|
26
27
|
this.args = [
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
name: "Windows",
|
|
30
|
+
type: "boolean",
|
|
31
|
+
value: true
|
|
31
32
|
},
|
|
32
33
|
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
name: "UNIX",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
value: true
|
|
36
37
|
},
|
|
37
38
|
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
name: "Display total",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "Sort",
|
|
45
|
+
type: "boolean",
|
|
46
|
+
value: false
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Unique",
|
|
50
|
+
type: "boolean",
|
|
51
|
+
value: false
|
|
41
52
|
}
|
|
42
53
|
];
|
|
43
54
|
}
|
|
@@ -48,7 +59,7 @@ class ExtractFilePaths extends Operation {
|
|
|
48
59
|
* @returns {string}
|
|
49
60
|
*/
|
|
50
61
|
run(input, args) {
|
|
51
|
-
const [includeWinPath, includeUnixPath, displayTotal] = args,
|
|
62
|
+
const [includeWinPath, includeUnixPath, displayTotal, sort, unique] = args,
|
|
52
63
|
winDrive = "[A-Z]:\\\\",
|
|
53
64
|
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
|
|
54
65
|
winExt = "[A-Z\\d]{1,6}",
|
|
@@ -65,12 +76,25 @@ class ExtractFilePaths extends Operation {
|
|
|
65
76
|
filePaths = unixPath;
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
if (filePaths) {
|
|
69
|
-
const regex = new RegExp(filePaths, "ig");
|
|
70
|
-
return search(input, regex, null, displayTotal);
|
|
71
|
-
} else {
|
|
79
|
+
if (!filePaths) {
|
|
72
80
|
return "";
|
|
73
81
|
}
|
|
82
|
+
|
|
83
|
+
const regex = new RegExp(filePaths, "ig");
|
|
84
|
+
const results = search(
|
|
85
|
+
input,
|
|
86
|
+
regex,
|
|
87
|
+
null,
|
|
88
|
+
sort ? caseInsensitiveSort : null,
|
|
89
|
+
unique
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (displayTotal) {
|
|
93
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
94
|
+
} else {
|
|
95
|
+
return results.join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
74
98
|
}
|
|
75
99
|
|
|
76
100
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import { search } from "../lib/Extract.mjs";
|
|
9
|
+
import { ipSort } from "../lib/Sort.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Extract IP addresses operation
|
|
@@ -25,24 +26,34 @@ class ExtractIPAddresses extends Operation {
|
|
|
25
26
|
this.outputType = "string";
|
|
26
27
|
this.args = [
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
name: "IPv4",
|
|
30
|
+
type: "boolean",
|
|
31
|
+
value: true
|
|
31
32
|
},
|
|
32
33
|
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
name: "IPv6",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
value: false
|
|
36
37
|
},
|
|
37
38
|
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
name: "Remove local IPv4 addresses",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
41
42
|
},
|
|
42
43
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
name: "Display total",
|
|
45
|
+
type: "boolean",
|
|
46
|
+
value: false
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Sort",
|
|
50
|
+
type: "boolean",
|
|
51
|
+
value: false
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "Unique",
|
|
55
|
+
type: "boolean",
|
|
56
|
+
value: false
|
|
46
57
|
}
|
|
47
58
|
];
|
|
48
59
|
}
|
|
@@ -53,7 +64,7 @@ class ExtractIPAddresses extends Operation {
|
|
|
53
64
|
* @returns {string}
|
|
54
65
|
*/
|
|
55
66
|
run(input, args) {
|
|
56
|
-
const [includeIpv4, includeIpv6, removeLocal, displayTotal] = args,
|
|
67
|
+
const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args,
|
|
57
68
|
ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
|
|
58
69
|
ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})";
|
|
59
70
|
let ips = "";
|
|
@@ -66,23 +77,29 @@ class ExtractIPAddresses extends Operation {
|
|
|
66
77
|
ips = ipv6;
|
|
67
78
|
}
|
|
68
79
|
|
|
69
|
-
if (ips)
|
|
70
|
-
const regex = new RegExp(ips, "ig");
|
|
80
|
+
if (!ips) return "";
|
|
71
81
|
|
|
72
|
-
|
|
73
|
-
const ten = "10\\..+",
|
|
74
|
-
oneninetwo = "192\\.168\\..+",
|
|
75
|
-
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
|
|
76
|
-
onetwoseven = "127\\..+",
|
|
77
|
-
removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
|
|
78
|
-
"|" + oneseventwo + "|" + onetwoseven + ")");
|
|
82
|
+
const regex = new RegExp(ips, "ig");
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
const ten = "10\\..+",
|
|
85
|
+
oneninetwo = "192\\.168\\..+",
|
|
86
|
+
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
|
|
87
|
+
onetwoseven = "127\\..+",
|
|
88
|
+
removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
|
|
89
|
+
"|" + oneseventwo + "|" + onetwoseven + ")");
|
|
90
|
+
|
|
91
|
+
const results = search(
|
|
92
|
+
input,
|
|
93
|
+
regex,
|
|
94
|
+
removeLocal ? removeRegex : null,
|
|
95
|
+
sort ? ipSort : null,
|
|
96
|
+
unique
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (displayTotal) {
|
|
100
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
84
101
|
} else {
|
|
85
|
-
return "";
|
|
102
|
+
return results.join("\n");
|
|
86
103
|
}
|
|
87
104
|
}
|
|
88
105
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import { search } from "../lib/Extract.mjs";
|
|
9
|
+
import { hexadecimalSort } from "../lib/Sort.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Extract MAC addresses operation
|
|
@@ -25,9 +26,19 @@ class ExtractMACAddresses extends Operation {
|
|
|
25
26
|
this.outputType = "string";
|
|
26
27
|
this.args = [
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
name: "Display total",
|
|
30
|
+
type: "boolean",
|
|
31
|
+
value: false
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "Sort",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
value: false
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "Unique",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
31
42
|
}
|
|
32
43
|
];
|
|
33
44
|
}
|
|
@@ -38,10 +49,21 @@ class ExtractMACAddresses extends Operation {
|
|
|
38
49
|
* @returns {string}
|
|
39
50
|
*/
|
|
40
51
|
run(input, args) {
|
|
41
|
-
const displayTotal = args
|
|
42
|
-
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig
|
|
52
|
+
const [displayTotal, sort, unique] = args,
|
|
53
|
+
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig,
|
|
54
|
+
results = search(
|
|
55
|
+
input,
|
|
56
|
+
regex,
|
|
57
|
+
null,
|
|
58
|
+
sort ? hexadecimalSort : null,
|
|
59
|
+
unique
|
|
60
|
+
);
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
if (displayTotal) {
|
|
63
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
64
|
+
} else {
|
|
65
|
+
return results.join("\n");
|
|
66
|
+
}
|
|
45
67
|
}
|
|
46
68
|
|
|
47
69
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import { search, URL_REGEX } from "../lib/Extract.mjs";
|
|
9
|
+
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Extract URLs operation
|
|
@@ -25,9 +26,19 @@ class ExtractURLs extends Operation {
|
|
|
25
26
|
this.outputType = "string";
|
|
26
27
|
this.args = [
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
name: "Display total",
|
|
30
|
+
type: "boolean",
|
|
31
|
+
value: false
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "Sort",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
value: false
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "Unique",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
31
42
|
}
|
|
32
43
|
];
|
|
33
44
|
}
|
|
@@ -38,8 +49,20 @@ class ExtractURLs extends Operation {
|
|
|
38
49
|
* @returns {string}
|
|
39
50
|
*/
|
|
40
51
|
run(input, args) {
|
|
41
|
-
const displayTotal = args
|
|
42
|
-
|
|
52
|
+
const [displayTotal, sort, unique] = args;
|
|
53
|
+
const results = search(
|
|
54
|
+
input,
|
|
55
|
+
URL_REGEX,
|
|
56
|
+
null,
|
|
57
|
+
sort ? caseInsensitiveSort : null,
|
|
58
|
+
unique
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
if (displayTotal) {
|
|
62
|
+
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
|
63
|
+
} else {
|
|
64
|
+
return results.join("\n");
|
|
65
|
+
}
|
|
43
66
|
}
|
|
44
67
|
|
|
45
68
|
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author n1474335 [n1474335@gmail.com]
|
|
3
|
+
* @copyright Crown Copyright 2022
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Operation from "../Operation.mjs";
|
|
8
|
+
import Stream from "../lib/Stream.mjs";
|
|
9
|
+
import {toHexFast, fromHex} from "../lib/Hex.mjs";
|
|
10
|
+
import {toBinary} from "../lib/Binary.mjs";
|
|
11
|
+
import {objToTable, bytesToLargeNumber} from "../lib/Protocol.mjs";
|
|
12
|
+
import Utils from "../Utils.mjs";
|
|
13
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
14
|
+
import BigNumber from "bignumber.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Parse TCP operation
|
|
18
|
+
*/
|
|
19
|
+
class ParseTCP extends Operation {
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ParseTCP constructor
|
|
23
|
+
*/
|
|
24
|
+
constructor() {
|
|
25
|
+
super();
|
|
26
|
+
|
|
27
|
+
this.name = "Parse TCP";
|
|
28
|
+
this.module = "Default";
|
|
29
|
+
this.description = "Parses a TCP header and payload (if present).";
|
|
30
|
+
this.infoURL = "https://wikipedia.org/wiki/Transmission_Control_Protocol";
|
|
31
|
+
this.inputType = "string";
|
|
32
|
+
this.outputType = "json";
|
|
33
|
+
this.presentType = "html";
|
|
34
|
+
this.args = [
|
|
35
|
+
{
|
|
36
|
+
name: "Input format",
|
|
37
|
+
type: "option",
|
|
38
|
+
value: ["Hex", "Raw"]
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} input
|
|
45
|
+
* @param {Object[]} args
|
|
46
|
+
* @returns {html}
|
|
47
|
+
*/
|
|
48
|
+
run(input, args) {
|
|
49
|
+
const format = args[0];
|
|
50
|
+
|
|
51
|
+
if (format === "Hex") {
|
|
52
|
+
input = fromHex(input);
|
|
53
|
+
} else if (format === "Raw") {
|
|
54
|
+
input = Utils.strToArrayBuffer(input);
|
|
55
|
+
} else {
|
|
56
|
+
throw new OperationError("Unrecognised input format.");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const s = new Stream(new Uint8Array(input));
|
|
60
|
+
if (s.length < 20) {
|
|
61
|
+
throw new OperationError("Need at least 20 bytes for a TCP Header");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Parse Header
|
|
65
|
+
const TCPPacket = {
|
|
66
|
+
"Source port": s.readInt(2),
|
|
67
|
+
"Destination port": s.readInt(2),
|
|
68
|
+
"Sequence number": bytesToLargeNumber(s.getBytes(4)),
|
|
69
|
+
"Acknowledgement number": s.readInt(4),
|
|
70
|
+
"Data offset": s.readBits(4),
|
|
71
|
+
"Flags": {
|
|
72
|
+
"Reserved": toBinary(s.readBits(3), "", 3),
|
|
73
|
+
"NS": s.readBits(1),
|
|
74
|
+
"CWR": s.readBits(1),
|
|
75
|
+
"ECE": s.readBits(1),
|
|
76
|
+
"URG": s.readBits(1),
|
|
77
|
+
"ACK": s.readBits(1),
|
|
78
|
+
"PSH": s.readBits(1),
|
|
79
|
+
"RST": s.readBits(1),
|
|
80
|
+
"SYN": s.readBits(1),
|
|
81
|
+
"FIN": s.readBits(1),
|
|
82
|
+
},
|
|
83
|
+
"Window size": s.readInt(2),
|
|
84
|
+
"Checksum": "0x" + toHexFast(s.getBytes(2)),
|
|
85
|
+
"Urgent pointer": "0x" + toHexFast(s.getBytes(2))
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Parse options if present
|
|
89
|
+
let windowScaleShift = 0;
|
|
90
|
+
if (TCPPacket["Data offset"] > 5) {
|
|
91
|
+
let remainingLength = TCPPacket["Data offset"] * 4 - 20;
|
|
92
|
+
|
|
93
|
+
const options = {};
|
|
94
|
+
while (remainingLength > 0) {
|
|
95
|
+
const option = {
|
|
96
|
+
"Kind": s.readInt(1)
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
let opt = { name: "Reserved", length: true };
|
|
100
|
+
if (Object.prototype.hasOwnProperty.call(TCP_OPTION_KIND_LOOKUP, option.Kind)) {
|
|
101
|
+
opt = TCP_OPTION_KIND_LOOKUP[option.Kind];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Add Length and Value fields
|
|
105
|
+
if (opt.length) {
|
|
106
|
+
option.Length = s.readInt(1);
|
|
107
|
+
|
|
108
|
+
if (option.Length > 2) {
|
|
109
|
+
if (Object.prototype.hasOwnProperty.call(opt, "parser")) {
|
|
110
|
+
option.Value = opt.parser(s.getBytes(option.Length - 2));
|
|
111
|
+
} else {
|
|
112
|
+
option.Value = option.Length <= 6 ?
|
|
113
|
+
s.readInt(option.Length - 2):
|
|
114
|
+
"0x" + toHexFast(s.getBytes(option.Length - 2));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Store Window Scale shift for later
|
|
118
|
+
if (option.Kind === 3 && option.Value) {
|
|
119
|
+
windowScaleShift = option.Value["Shift count"];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
options[opt.name] = option;
|
|
124
|
+
|
|
125
|
+
const length = option.Length || 1;
|
|
126
|
+
remainingLength -= length;
|
|
127
|
+
}
|
|
128
|
+
TCPPacket.Options = options;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (s.hasMore()) {
|
|
132
|
+
TCPPacket.Data = "0x" + toHexFast(s.getBytes());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Improve values
|
|
136
|
+
TCPPacket["Data offset"] = `${TCPPacket["Data offset"]} (${TCPPacket["Data offset"] * 4} bytes)`;
|
|
137
|
+
const trueWndSize = BigNumber(TCPPacket["Window size"]).multipliedBy(BigNumber(2).pow(BigNumber(windowScaleShift)));
|
|
138
|
+
TCPPacket["Window size"] = `${TCPPacket["Window size"]} (Scaled: ${trueWndSize})`;
|
|
139
|
+
|
|
140
|
+
return TCPPacket;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Displays the TCP Packet in a tabular style
|
|
145
|
+
* @param {Object} data
|
|
146
|
+
* @returns {html}
|
|
147
|
+
*/
|
|
148
|
+
present(data) {
|
|
149
|
+
return objToTable(data);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Taken from https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml
|
|
155
|
+
// on 2022-05-30
|
|
156
|
+
const TCP_OPTION_KIND_LOOKUP = {
|
|
157
|
+
0: { name: "End of Option List", length: false },
|
|
158
|
+
1: { name: "No-Operation", length: false },
|
|
159
|
+
2: { name: "Maximum Segment Size", length: true },
|
|
160
|
+
3: { name: "Window Scale", length: true, parser: windowScaleParser },
|
|
161
|
+
4: { name: "SACK Permitted", length: true },
|
|
162
|
+
5: { name: "SACK", length: true },
|
|
163
|
+
6: { name: "Echo (obsoleted by option 8)", length: true },
|
|
164
|
+
7: { name: "Echo Reply (obsoleted by option 8)", length: true },
|
|
165
|
+
8: { name: "Timestamps", length: true, parser: tcpTimestampParser },
|
|
166
|
+
9: { name: "Partial Order Connection Permitted (obsolete)", length: true },
|
|
167
|
+
10: { name: "Partial Order Service Profile (obsolete)", length: true },
|
|
168
|
+
11: { name: "CC (obsolete)", length: true },
|
|
169
|
+
12: { name: "CC.NEW (obsolete)", length: true },
|
|
170
|
+
13: { name: "CC.ECHO (obsolete)", length: true },
|
|
171
|
+
14: { name: "TCP Alternate Checksum Request (obsolete)", length: true, parser: tcpAlternateChecksumParser },
|
|
172
|
+
15: { name: "TCP Alternate Checksum Data (obsolete)", length: true },
|
|
173
|
+
16: { name: "Skeeter", length: true },
|
|
174
|
+
17: { name: "Bubba", length: true },
|
|
175
|
+
18: { name: "Trailer Checksum Option", length: true },
|
|
176
|
+
19: { name: "MD5 Signature Option (obsoleted by option 29)", length: true },
|
|
177
|
+
20: { name: "SCPS Capabilities", length: true },
|
|
178
|
+
21: { name: "Selective Negative Acknowledgements", length: true },
|
|
179
|
+
22: { name: "Record Boundaries", length: true },
|
|
180
|
+
23: { name: "Corruption experienced", length: true },
|
|
181
|
+
24: { name: "SNAP", length: true },
|
|
182
|
+
25: { name: "Unassigned (released 2000-12-18)", length: true },
|
|
183
|
+
26: { name: "TCP Compression Filter", length: true },
|
|
184
|
+
27: { name: "Quick-Start Response", length: true },
|
|
185
|
+
28: { name: "User Timeout Option (also, other known unauthorized use)", length: true },
|
|
186
|
+
29: { name: "TCP Authentication Option (TCP-AO)", length: true },
|
|
187
|
+
30: { name: "Multipath TCP (MPTCP)", length: true },
|
|
188
|
+
69: { name: "Encryption Negotiation (TCP-ENO)", length: true },
|
|
189
|
+
70: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
|
|
190
|
+
76: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
|
|
191
|
+
77: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
|
|
192
|
+
78: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
|
|
193
|
+
253: { name: "RFC3692-style Experiment 1 (also improperly used for shipping products) ", length: true },
|
|
194
|
+
254: { name: "RFC3692-style Experiment 2 (also improperly used for shipping products) ", length: true }
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Parses the TCP Alternate Checksum Request field
|
|
199
|
+
* @param {Uint8Array} data
|
|
200
|
+
*/
|
|
201
|
+
function tcpAlternateChecksumParser(data) {
|
|
202
|
+
const lookup = {
|
|
203
|
+
0: "TCP Checksum",
|
|
204
|
+
1: "8-bit Fletchers's algorithm",
|
|
205
|
+
2: "16-bit Fletchers's algorithm",
|
|
206
|
+
3: "Redundant Checksum Avoidance"
|
|
207
|
+
}[data[0]];
|
|
208
|
+
|
|
209
|
+
return `${lookup} (0x${toHexFast(data)})`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Parses the TCP Timestamp field
|
|
214
|
+
* @param {Uint8Array} data
|
|
215
|
+
*/
|
|
216
|
+
function tcpTimestampParser(data) {
|
|
217
|
+
const s = new Stream(data);
|
|
218
|
+
|
|
219
|
+
if (s.length !== 8)
|
|
220
|
+
return `Error: Timestamp field should be 8 bytes long (received 0x${toHexFast(data)})`;
|
|
221
|
+
|
|
222
|
+
const tsval = bytesToLargeNumber(s.getBytes(4)),
|
|
223
|
+
tsecr = bytesToLargeNumber(s.getBytes(4));
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
"Current Timestamp": tsval,
|
|
227
|
+
"Echo Reply": tsecr
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Parses the Window Scale field
|
|
233
|
+
* @param {Uint8Array} data
|
|
234
|
+
*/
|
|
235
|
+
function windowScaleParser(data) {
|
|
236
|
+
if (data.length !== 1)
|
|
237
|
+
return `Error: Window Scale should be one byte long (received 0x${toHexFast(data)})`;
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
"Shift count": data[0],
|
|
241
|
+
"Multiplier": 1 << data[0]
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export default ParseTCP;
|