Skip to content

Commit

Permalink
Failing TLS proxy code
Browse files Browse the repository at this point in the history
  • Loading branch information
pimterry committed Dec 5, 2017
0 parents commit 6efeb12
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
119 changes: 119 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Node TLS crash demo

## Repro:

* Checkout
* `npm install`
* `npm start`
* Start chrome using this as a proxy
* Node will segfault with a minute or two

This module is a minimal POC implementation of an HTTPS intercepting proxy. It's using no native modules at all, but it still reliably
crashes with SIGSEGV/SIGABRT in recent Node versions.

## Details

Running `npm start` starts an intercepting HTTPS proxy server on port 8000. You'll need to disable cert validation or trust `test-ca.pem` as a CA to use it.

E.g. with curl:

```bash
curl -k --proxy-insecure -x https://localhost:8000 https://example.com
```

You can start a fresh Chrome session using this proxy & trusting the cert with:

```
google-chrome --user-data-dir=/tmp/chrome --proxy-server="https://localhost:80" --ignore-certificate-errors-spki-list=AvVrqB/anBbJ+KRCMH/anWgZbeE0Y28JtqYB0+2MDmE=
```

After a minute of heavy use the proxy will crash with SIGSEGV/SIGABRT, I think always in CRYPTO_free, and typically inside DestroySSL.

The easiest repro for me is just to open `https://cnn.com` in a few tabs. This fails in at least Node 8.9.1 and 6.12.0 (though v6 seems to take longer).

Note that this code doesn't use any native modules - it's pure JS all the way down (according to `find node_modules/ -name \*.node`), so this
is a crash coming directly from Node itself.

Failures typically look something like:

```
*** Error in `node': free(): invalid next size (fast): 0x0000000003ea2660 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7908b)[0x7f3ba3ff908b]
/lib/x86_64-linux-gnu/libc.so.6(+0x82c3a)[0x7f3ba4002c3a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f3ba4006d2c]
node(CRYPTO_free+0x25)[0x997995]
node(ASN1_primitive_free+0x6f)[0x90ed0f]
node(asn1_item_combine_free+0x93)[0x90eea3]
node(ASN1_item_free+0x2b2)[0x90f502]
node(sk_pop_free+0x37)[0x9d2767]
node[0x913a3d]
node(asn1_item_combine_free+0x5e)[0x90ee6e]
node(asn1_item_combine_free+0x2e2)[0x90f0f2]
node(ASN1_item_free+0x2b2)[0x90f502]
node(sk_pop_free+0x37)[0x9d2767]
node(ssl_sess_cert_free+0x53)[0x8d3793]
node(SSL_SESSION_free+0x8f)[0x8e0fcf]
node(SSL_free+0xf5)[0x8db195]
node(_ZN4node6crypto7SSLWrapINS_7TLSWrapEE10DestroySSLEv+0x1a)[0x12dd7ea]
node(_ZN4node7TLSWrap10DestroySSLERKN2v820FunctionCallbackInfoINS1_5ValueEEE+0xb8)[0x12e33b8]
node(_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE+0x193)[0xb1a073]
node[0xb8fe3c]
node(_ZN2v88internal21Builtin_HandleApiCallEiPPNS0_6ObjectEPNS0_7IsolateE+0xaf)[0xb90a8f]
[0x15bab148463d]
```

```
*** Error in `node': free(): invalid pointer: 0x0000000002ff6580 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7908b)[0x7f78f945b08b]
/lib/x86_64-linux-gnu/libc.so.6(+0x82c3a)[0x7f78f9464c3a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f78f9468d2c]
node(CRYPTO_free+0x25)[0x997995]
node(sk_free+0x1f)[0x9d27df]
node(asn1_item_combine_free+0x1f4)[0x90f004]
node(ASN1_item_free+0x2b2)[0x90f502]
node(_ZN4node6crypto13SecureContextD0Ev+0x3f)[0x12d76ef]
node(_ZN2v88internal13GlobalHandles31DispatchPendingPhantomCallbacksEb+0xee)[0xe7b01e]
node(_ZN2v88internal13GlobalHandles31PostGarbageCollectionProcessingENS0_16GarbageCollectorENS_15GCCallbackFlagsE+0x2a)[0xe7b28a]
node(_ZN2v88internal4Heap24PerformGarbageCollectionENS0_16GarbageCollectorENS_15GCCallbackFlagsE+0x2be)[0xea660e]
node[0xea7933]
node(_ZN2v88internal4Heap36FinalizeIncrementalMarkingIfCompleteENS0_23GarbageCollectionReasonE+0x4a)[0xea86ca]
node(_ZN2v88internal21IncrementalMarkingJob4Task11RunInternalEv+0x119)[0xeaa0d9]
node(_ZN2v88internal14CancelableTask3RunEv+0x36)[0xbc83e6]
node(_ZN4node12NodePlatform28FlushForegroundTasksInternalEv+0x1f4)[0x1272174]
node[0x145796b]
node[0x14694c8]
node(uv_run+0x156)[0x14582f6]
node(_ZN4node5StartEP9uv_loop_siPKPKciS5_+0xc75)[0x122af15]
node(_ZN4node5StartEiPPc+0x163)[0x1223b73]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f78f94023f1]
node[0x8ae7c1]
```

```
*** Error in `node': corrupted size vs. prev_size: 0x0000000003fd6060 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7908b)[0x7f66633b608b]
/lib/x86_64-linux-gnu/libc.so.6(+0x814a7)[0x7f66633be4a7]
/lib/x86_64-linux-gnu/libc.so.6(+0x82f20)[0x7f66633bff20]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f66633c3d2c]
node(CRYPTO_free+0x25)[0x997995]
node(SSL_CTX_free+0x1e3)[0x8da9b3]
node(_ZN4node6crypto13SecureContextD0Ev+0x31)[0x12d76e1]
node(_ZN2v88internal13GlobalHandles31DispatchPendingPhantomCallbacksEb+0xee)[0xe7b01e]
node(_ZN2v88internal13GlobalHandles31PostGarbageCollectionProcessingENS0_16GarbageCollectorENS_15GCCallbackFlagsE+0x2a)[0xe7b28a]
node(_ZN2v88internal4Heap24PerformGarbageCollectionENS0_16GarbageCollectorENS_15GCCallbackFlagsE+0x2be)[0xea660e]
node[0xea7933]
node(_ZN2v88internal4Heap36FinalizeIncrementalMarkingIfCompleteENS0_23GarbageCollectionReasonE+0x4a)[0xea86ca]
node(_ZN2v88internal21IncrementalMarkingJob4Task11RunInternalEv+0x119)[0xeaa0d9]
node(_ZN2v88internal14CancelableTask3RunEv+0x36)[0xbc83e6]
node(_ZN4node12NodePlatform28FlushForegroundTasksInternalEv+0x1f4)[0x1272174]
node[0x145796b]
node[0x14694c8]
node(uv_run+0x156)[0x14582f6]
node(_ZN4node5StartEP9uv_loop_siPKPKciS5_+0xc75)[0x122af15]
node(_ZN4node5StartEiPPc+0x163)[0x1223b73]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f666335d3f1]
node[0x8ae7c1]
```
14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "tls-crash-demo",
"version": "1.0.0",
"description": "",
"main": "proxy.js",
"scripts": {
"start": "node proxy.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"mockttp": "^0.4.0"
}
}
58 changes: 58 additions & 0 deletions proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const https = require('https');
const tls = require('tls');
const fs = require('fs');

const { CA } = require('mockttp/dist/util/tls');

const port = 8000;

const caKey = fs.readFileSync('./test-ca.key');
const caCert = fs.readFileSync('./test-ca.pem');

const ca = new CA(caKey, caCert);

const serverCert = ca.generateCertificate('localhost');
const server = https.createServer({
key: caKey,
cert: caCert,
ca: [caCert],
SNICallback: (domain, cb) => {
const generatedCert = ca.generateCertificate(domain);
cb(null, tls.createSecureContext(generatedCert));
}
});

server.addListener('connect', (req, socket, head) => {
console.log(`Proxying request to ${req.url}`);
let [ targetHost, port ] = req.url.split(':');
port = parseInt(port, 10);

// Note that the CA caches generated certificates by domain, so this is typically fairly cheap.
// This is pure JS with node-forge, source at https://unpkg.com/[email protected]/dist/util/tls.js
const { key, cert } = ca.generateCertificate(targetHost);

socket.write('HTTP/' + req.httpVersion + ' 200 OK\r\n\r\n', 'UTF-8', () => {
let tlsSocket = new tls.TLSSocket(socket, {
isServer: true,
secureContext: tls.createSecureContext({
key,
cert,
ca: caCert
})
});

let upstream = tls.connect(port, targetHost, {}, () => {
upstream.write(head);

tlsSocket.pipe(upstream);
upstream.pipe(tlsSocket);
});

upstream.on('error', (e) => {
console.log(`Upstream error for ${targetHost}`, e);
socket.destroy(e);
});
});
});

server.listen(port, (err) => console.log(err || `Listening on ${port}`));
28 changes: 28 additions & 0 deletions test-ca.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDNfC2Wrf1+skkr
eS53j4BNHjL6579cu/mK/VX1oENG/FTqEw7QC4bO6y56h1dLaCtgaUutmtfAlM9T
AQBBAzRMriNmXqzu/lHp3AoH57/1WbQ5skRzwn2zUU9ktPm63dWsFnJI/k9thL1a
D+vnakJAzjj7J4agFs91Ll3FLDzX44g4ptVERAP9aQ9HlooU991e1EDchNuRynTM
E+oHV+s7oV0jWq5m3m0KeJrVtug9NdtcUTTQCzlC9OXBBiGlspAr8lrLg8MnIAUY
A33nmbaINdqu1u8LxLVjTfmQJI4e19FGfiyMJLX9iFhT+ATnpt6itAoXkIR/nKYi
CIxcTqLlAgMBAAECggEBALYMRB9wulsa/PRFAkPuoM6x6Jyd4M35w5W96AAbIj+r
oldW1xK+g4qilaT8bvxhp7xczS1bN7ZooF17T4xJmHYu+THiwvdh3ZSA22oxicGG
3cMYCsk8ED1j1iD0rSM/EeTKZioBFMGEjnVSEcAORfBAQ/9O/1ipnNbGY1EiZi0k
0lIKcCwLmyXWTK07o40W2l2cxpJddcM1ZSWr5jiw6SNfuhIDMelM+ctvFcdBp2HJ
6RP40e4nCliz+bBsjJ9rI9JnxJ4Zx11CI0a7Fi4B3va1Pips58wvZhm1V6PzRVyx
WPm1Sjj0hLmzjpwGX5XdTfGAaw71ekJpr1ZXnbVItSkCgYEA+dXGKsKvgI+WamM1
EpDwvBUGwWyA7MSUDX10iT/vawUP7jmvwASvcSbsOy8n5kvm2zyCA/5ZPGJvEvNK
mHASenbBXlPmSbUg31Ju1ndTf4KLkmPHldzR0Wg7lzYypP1mKh1ZeZzr3jLLc35g
CRyHorAudlxipDOKFiLdQl3Jgp8CgYEA0o498Y+O0gcX/OP9yG2Osap9Ixj64EHs
sOPUfYPElvHzPyngPwF6zDLNVOiZrv4dnW6S1vLveYFWjm9HuzVlqLVg2wC+nYrS
baURB7phwjJUBzLyRh9e4qKwmjwygbhhmvpqLXPw3tq00KkFui9u+AR7l6q0W0aU
PBC9TwjDz/sCgYEAvZqAh2kzGkVeqSTbXVjEamkmtFqtSYMyvT4t2A++mqC/41LC
T97+ashYVd5G0J9f95hnL7KzdIFbvK0JOsErNOe1fun7horBBNshpP/wTX/8fr/c
854fWmZZezu1mcN56pJVmlb+Jqa0AtWw+pk9UrmUuV0Ju4Yl0QDqnHhi+w8CgYBe
SDdQjXnkbiy9ntGrB/PXdoImTy83cA2uf7ZMpc5H0PudEwFI9T6pZS4wkR8QDtXw
Au1Zttqoy9OYYBf8qkJlMyK1rjWskdb8JefkT/8qWCLsPlHiOHXigfsWdVIgaBG8
tdkJlVsMT16b+LOJ1WeZQ1icZ2HvZUFHTC+YzlHwNQKBgQCUp1NT93fXNs9mYU5l
Az0gsAdjECz6N7kNQWGrl883Y3YZ/wqrfir3UCKGxJ6270IkA+VPdSmplCPf1zwQ
TmppzR3WuKqlj29W0qavT+4f/67aKTZGormo+QfXjL6kkXRGJ0xLsentcuoM7zCC
gIBTGAb9wqjI1WPO6ImlPYVxjA==
-----END PRIVATE KEY-----
19 changes: 19 additions & 0 deletions test-ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKzCCAhOgAwIBAgIJAP4Z15C7V0rSMA0GCSqGSIb3DQEBCwUAMCwxKjAoBgNV
BAMMIU1vY2t0dHAgVGVzdGluZyBDQSAtIERPIE5PVCBUUlVTVDAeFw0xNzExMTQy
MTU2MDlaFw0xNzEyMTQyMTU2MDlaMCwxKjAoBgNVBAMMIU1vY2t0dHAgVGVzdGlu
ZyBDQSAtIERPIE5PVCBUUlVTVDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAM18LZat/X6ySSt5LnePgE0eMvrnv1y7+Yr9VfWgQ0b8VOoTDtALhs7rLnqH
V0toK2BpS62a18CUz1MBAEEDNEyuI2ZerO7+UencCgfnv/VZtDmyRHPCfbNRT2S0
+brd1awWckj+T22EvVoP6+dqQkDOOPsnhqAWz3UuXcUsPNfjiDim1UREA/1pD0eW
ihT33V7UQNyE25HKdMwT6gdX6zuhXSNarmbebQp4mtW26D0121xRNNALOUL05cEG
IaWykCvyWsuDwycgBRgDfeeZtog12q7W7wvEtWNN+ZAkjh7X0UZ+LIwktf2IWFP4
BOem3qK0CheQhH+cpiIIjFxOouUCAwEAAaNQME4wHQYDVR0OBBYEFGZVh4J+GvDD
iFJlD0ubhr4iD188MB8GA1UdIwQYMBaAFGZVh4J+GvDDiFJlD0ubhr4iD188MAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAL1PwkVVCuJoSn4PLdw3MmUP
YBtrTnC4n6v1p2uHNktWA5Mq0AyLggdp4URlBunsfPCEwx3/dbNimOmav/rHIsiC
uQgT6G3KT0Npr95EpO8GXka1vkYP1sI81j4ANR3h3smGXilFLSBQQfFkzRMg427z
ABP9PDiuwlYModoE5aXr0mhgW+gi8HffIWrzickbOdyZgrljB1ehHh1oiGTNs3gi
JAKhQc7bEejuyLI8pYovZVSKzdajGsr4+CZqqkz4OOxo3z+C55hCDyJILHJUlWS7
mSfkXJTIhnyW3gyMp6o3F0c2XvAqLAawnHo1lUXHcu7JChJAWDXRxdu4H1+jwQc=
-----END CERTIFICATE-----

0 comments on commit 6efeb12

Please sign in to comment.