├── .gitignore ├── README.md ├── cert.pem ├── key.pem ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | _tmp/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **As of September 2020 this no longer works, it was fun while it lasted.** 2 | 3 | --- 4 | 5 | gproxy 6 | ====== 7 | 8 | gproxy exploits a Google web service hosted at 9 | `images-onepick-opensocial.googleusercontent.com` (which is commonly used to 10 | fetch user-provided content, e.g., to load images by URL in Google Documents) to 11 | proxy arbitrary HTTP(S) traffic. 12 | 13 | Installation 14 | ------------ 15 | 16 | Install with: 17 | 18 | npm install -g git://github.com/cyrus-and/gproxy.git 19 | 20 | Note that a global installation is not mandatory; the proxy can be started with 21 | `npm start` from the main directory. In that case, it may be easier to download 22 | the [ZIP][zip] archive or clone the repo, instead of using `npm install`: 23 | 24 | git clone https://github.com/cyrus-and/gproxy.git 25 | 26 | Quick start 27 | ----------- 28 | 29 | Just run `gproxy` and follow the instructions to configure the clients. 30 | 31 | Advanced usage 32 | -------------- 33 | 34 | 1. Generate a self-signed certificate (or skip this step and use the one 35 | bundled, which has been created for `localhost`, as shown below): 36 | 37 | openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \ 38 | -subj '/CN=localhost' -keyout key.pem -out cert.pem 39 | 40 | Certificates (`key.pem` and `cert.pem`) in the current working directory will 41 | have the precedence over the one bundled. 42 | 43 | 2. Start the proxy, optionally also specifying host and port. By default gproxy 44 | listens on `localhost:8080` but this can be changed by setting two 45 | environment variables: `GPROXY_HOST` and `GPROXY_PORT`. For example with: 46 | 47 | export GPROXY_HOST=0.0.0.0 48 | export GPROXY_PORT=1234 49 | gproxy 50 | 51 | gproxy will listen on all the interfaces on port `1234`. 52 | 53 | 3. Use `http://localhost:8080` (or whatever has been chosen) as a proxy server 54 | in your client configuration for both HTTP and HTTPS traffic. Most programs 55 | look for specific environment variables like `http_proxy` and 56 | `https_proxy`. With Bash just: 57 | 58 | export http{,s}_proxy=http://localhost:8080 59 | 60 | Note that to load HTTPS websites the client must ignore certificate 61 | errors. Some examples: 62 | 63 | google-chrome --ignore-certificate-errors 64 | curl -k https://example.com 65 | wget --no-check-certificate https://example.com 66 | 67 | Caveats 68 | ------- 69 | 70 | * Custom client headers are not forwarded to the server (e.g., no cookies). 71 | 72 | * Redirects are performed by the server, this means that the client is not aware 73 | of the new location. 74 | 75 | * The `content-disposition` response header is lost. 76 | 77 | Disclaimer 78 | ---------- 79 | 80 | gproxy is just a PoC and should be treated as such. Proxying arbitrary web 81 | traffic is unlikely to be the original purpose of the aforementioned web 82 | service. Not to mention that even though the client identity is hidden to the 83 | final server, it is not to Google itself. 84 | 85 | [zip]: https://github.com/cyrus-and/gproxy/archive/master.zip 86 | -------------------------------------------------------------------------------- /cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC+zCCAeOgAwIBAgIJAIbugQIlQj49MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV 3 | BAMMCWxvY2FsaG9zdDAeFw0xNTA2MzAwMDUxNTZaFw0yNTA2MjcwMDUxNTZaMBQx 4 | EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBAKlfhQpr65qLLb470mI58/lR3aTGVdP9zWucn52OVho2tNRk+2IkK3L/0+4T 6 | FRsrhl37xqQEB1ep93TAtYLM7gMyswAWV0V5Lu8cglkTkxzDFZz42UDQlUbwTi69 7 | Lb/FRAu7IuIFLtwAghk5VNa3+xwQi7cpxssxaT9FZQBlAwCO93Ed2Z7u4ts+ZkBO 8 | OAFZ+MpMPCj0WEx7dQMrWIPLjlFz76wodR4VLrvWCilMVCr7u287pzTxaOEunB2o 9 | OKik6KbQWvDOAXlaqnlJw0tAIz89bvxcOkqoPJL9Ihmw5dGdCxn5kaCaSPW0REND 10 | cxnF1TY+DXYT7mgjY0s+SqroYAkCAwEAAaNQME4wHQYDVR0OBBYEFCIcZFOcx94P 11 | ELH9TIUL+pFG9fuhMB8GA1UdIwQYMBaAFCIcZFOcx94PELH9TIUL+pFG9fuhMAwG 12 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH2JzFj9FQztJ73ZuPU+gItC 13 | 4ys75f0IrU6+4wgLXLjQ4E2D0IJQCUSK8/hu0tydblbrnpRrkSs5UQnTRNiYdlMM 14 | l/llBWbEwGqAYLuEs2/JLE9RyfCf+zQgpfbsfjs5CgawTXjqCdVwBMl68u2dYap9 15 | 1w2HFCTl9M7CO8NZE60ooRO86N/laCIUKOAneKvcorVizZkHPttfJdwI8prQBzX/ 16 | 6Ou87Oyh3Rcwx4up0bDmEu1uGYw1asUni1jasP23BQE4Wv2FsQQkrGfpGZDUJEvy 17 | XCRvTIrxzXYc62jtf2o/x/4HDBl4lLB7NLNkw5RY07nU1vv2oi5Gfg77aprSKcY= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCpX4UKa+uaiy2+ 3 | O9JiOfP5Ud2kxlXT/c1rnJ+djlYaNrTUZPtiJCty/9PuExUbK4Zd+8akBAdXqfd0 4 | wLWCzO4DMrMAFldFeS7vHIJZE5McwxWc+NlA0JVG8E4uvS2/xUQLuyLiBS7cAIIZ 5 | OVTWt/scEIu3KcbLMWk/RWUAZQMAjvdxHdme7uLbPmZATjgBWfjKTDwo9FhMe3UD 6 | K1iDy45Rc++sKHUeFS671gopTFQq+7tvO6c08WjhLpwdqDiopOim0FrwzgF5Wqp5 7 | ScNLQCM/PW78XDpKqDyS/SIZsOXRnQsZ+ZGgmkj1tERDQ3MZxdU2Pg12E+5oI2NL 8 | Pkqq6GAJAgMBAAECggEADmhwwdUyYqAqUP93wyFY7sGXEDhK/tCdU+Ur8tQz4OD8 9 | ewDoHY4kIBFBLwRyjDAkqwQK/tLU6REtWsI17p2ONblvXreHzwIjCvYq5Hb00cKK 10 | qSLGIGxd9n3kuLchGCoowrK1ofJ87PwiFRE6dVWLR/TkXb1xCsH2SQqXL/Rnz/k2 11 | AV5NQ3LA0qMg1zGGv/KxXpDD9kvHxtR32U9ABvqEjPd5GSgQkK5lEHY+/Q7DA5u+ 12 | Vtt3VCuH1oXLsap1yf+RXNxgDoS1ftxtN/3+4Y79ivV+t9PbZH4YwdYN046bFDZl 13 | oY4mDjWqeFFnFSWcCcVRBf0YSZCAduLIJvDg+b7mDQKBgQDYX9metgn9wBgWLzwY 14 | 5y+hU4iS5erislyRoEEw41GbCZ32xuXaC4iBxwK3WHnEyNCcEJKe3R3KHgDY2P4+ 15 | r00VVU4VLz7JxxBNrYdKIQCaWtp36Yla8QBZCs8eie7fNRavuqgiFgO32a5meheW 16 | BpqlHWgx/VglM9+YPGdAVZMaZwKBgQDIZCMAX8dDuk7iKsTLyGijuVdQOLeJOjre 17 | KWtPbaokKZLtV0UwpKqgbU2tfgqfzjpHPvwjUHxrSNIZEfZF/sqD535IAtJOFDGn 18 | fMTGa/bug4qENu+P2Q8yGll4E55Fe7dzqnPBWmK9GdMbbiCmmN6O3EMtrspLjRt5 19 | bRxh32sMDwKBgQCNBdu2X3sfkYWhX+PRb0xR3znSVFvEqO9AUqxqip3zaE82Oegx 20 | Nvcfbm/Mw7OJmECulvaY6BC0XN28d6Ethd+9mb2sfQB1TnLHzeOxYtUbxT9CjElj 21 | plPNtQfNJaU0gUtp+UQAA00lFJFgZQ7eTyuXlhUFD9PVW3vNowDAo4We3QKBgFPg 22 | 1mXJsXa//VTd4hIKiQI/CjUiCHEAVrO3Upuko5sPa9i8ttFtm54bInCEWZ4ajHpV 23 | +uQtRGcDzC2CPzt9MveTZmBuDelwungI2bTUbD/Z/5joBc6IZLvsG5cPXyhmaJuZ 24 | tWoxkzLkJGFO74vMYRwbRmNQzoxhPCbPbRnqkrwxAoGAI/CvYhkGgX85JSnlLK/y 25 | Cz4z3GKsh/Ok4N0lUFUPwLbFxH9S+3vu7LcPquUOCDdyKqLN2gRhMoey1YC4uKve 26 | 0/Ss76bVDrhR/KJYEyg9hl/iqVd3ZxUiTZs8eyaeSCUGu2TAirP30ixWkPV6zRNl 27 | bsf0GBSC+NGtKjroU4075Jc= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gproxy", 3 | "author": "Andrea Cardaci ", 4 | "description": "googleusercontent.com as HTTP(S) proxy", 5 | "version": "0.0.0", 6 | "bin": "./server.js" 7 | } 8 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | var net = require('net'); 5 | var http = require('http'); 6 | var https = require('https'); 7 | var path = require('path'); 8 | 9 | var key_name = 'key.pem'; 10 | var cert_name = 'cert.pem'; 11 | 12 | var host = process.env.GPROXY_HOST || 'localhost'; 13 | var port = process.env.GPROXY_PORT || 8080; 14 | var https_port; 15 | 16 | function connect_handler(request, socket, head) { 17 | var client = net.connect(https_port, function () { 18 | socket.write('HTTP/1.1 200 Connection established\r\n\r\n', function () { 19 | client.pipe(socket); 20 | socket.pipe(client); 21 | }); 22 | }); 23 | client.on('error', function () {}); 24 | } 25 | 26 | function request_handler(request, response) { 27 | var url; 28 | if (request.url[0] === '/') { 29 | url = 'https://' + request.headers.host + request.url; 30 | } else { 31 | url = request.url; 32 | } 33 | 34 | console.log(request.method, url); 35 | 36 | var options = { 37 | 'host': 'images-onepick-opensocial.googleusercontent.com', 38 | 'method': request.method, 39 | 'path': '/gadgets/proxy?container=onepick&url=' + encodeURIComponent(url) 40 | }; 41 | 42 | var proxy_request = https.request(options, function (proxy_response) { 43 | delete proxy_response.headers['content-disposition']; 44 | response.writeHead(proxy_response.statusCode, proxy_response.headers); 45 | proxy_response.pipe(response); 46 | }); 47 | 48 | request.pipe(proxy_request); 49 | } 50 | 51 | try { 52 | var key = fs.readFileSync(key_name); 53 | var cert = fs.readFileSync(cert_name); 54 | } catch (err) { 55 | console.log('# Falling back to the bundled certificate'); 56 | process.chdir(__dirname); 57 | key = fs.readFileSync(key_name); 58 | cert = fs.readFileSync(cert_name); 59 | } 60 | 61 | var http_server = http.createServer(); 62 | var https_server = https.createServer({'key': key, 'cert': cert}); 63 | 64 | http_server.on('connect', connect_handler); 65 | http_server.on('request', request_handler); 66 | https_server.on('request', request_handler); 67 | 68 | https_server.listen(0, 'localhost', function () { 69 | https_port = https_server.address().port; 70 | http_server.listen(port, host, function () { 71 | console.log('# Listening on ' + host + ' on port ' + port); 72 | console.log('#'); 73 | console.log('# Client setup (Bash):'); 74 | console.log('#'); 75 | console.log('# export http{,s}_proxy=http://' + host + ':' + port); 76 | console.log('# unset http{,s}_proxy'); 77 | console.log('#'); 78 | }); 79 | }); 80 | --------------------------------------------------------------------------------