From e3c5c15a7cb15d990027dd2bcc8716d7686cca84 Mon Sep 17 00:00:00 2001 From: zefie Date: Sun, 11 Jul 2021 18:28:53 -0400 Subject: [PATCH] fix challenge exchange and tickets --- README.md | 5 + .../wtv-1800 => ServiceDeps/LC2}/LC2.tok | 12 +- .../LC2/artemis_18004653537.tok | Bin .../LC2/artemis_18006138199.tok | Bin hacktv_updsrv/ServiceDeps/splash.html | 21 + hacktv_updsrv/ServiceVault/wtv-1800/mame.jpg | Bin 0 -> 13922 bytes .../wtv-1800/offer-open-isp-suggest.js | 25 +- .../ServiceVault/wtv-1800/preregister.js | 3 +- .../wtv-head-waiter/login-stage-two.js | 50 ++- .../ServiceVault/wtv-head-waiter/login.js | 77 ++-- hacktv_updsrv/app.js | 376 ++++++++++++------ hacktv_updsrv/package-lock.json | 33 +- hacktv_updsrv/package.json | 5 +- hacktv_updsrv/wtvsec.js | 95 +++-- 14 files changed, 485 insertions(+), 217 deletions(-) create mode 100644 README.md rename hacktv_updsrv/{ServiceVault/wtv-1800 => ServiceDeps/LC2}/LC2.tok (85%) rename hacktv_updsrv/{ServiceVault/wtv-1800 => ServiceDeps}/LC2/artemis_18004653537.tok (100%) rename hacktv_updsrv/{ServiceVault/wtv-1800 => ServiceDeps}/LC2/artemis_18006138199.tok (100%) create mode 100644 hacktv_updsrv/ServiceDeps/splash.html create mode 100644 hacktv_updsrv/ServiceVault/wtv-1800/mame.jpg diff --git a/README.md b/README.md new file mode 100644 index 00000000..78b7ed6f --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# wtv minisrv node.js + +The ***wtv minisrv***, or "***hacktv_updsrv***" project is an ambitious node.js project to have a mini WebTV server that supports wtv-encryption for advanced level access. + +This open source server is not yet ready for public use, but is available for anyone wanting to try to help advance it. diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok b/hacktv_updsrv/ServiceDeps/LC2/LC2.tok similarity index 85% rename from hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok rename to hacktv_updsrv/ServiceDeps/LC2/LC2.tok index be9e10b6..adaab7b4 100644 --- a/hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok +++ b/hacktv_updsrv/ServiceDeps/LC2/LC2.tok @@ -1,5 +1,4 @@ -ANDY........z. -.`.6[......8(&.S.....}...lIa.;...b..c..d....e...f..g%.c*I.h..i!...j).k.B.lH.m.=C5*@.n +ANDY...........r`.{....}..8..".,....}...lIa.;...b..c..d....e...f..g%.c*I.h..i!...j).k.B.lH.m.=C5*@.n .1].oQ.t..Ip.().{..Isetdtr..(C.);.Idoelay..1>..z..1....rC...}M.q.(..r..R.lIs|...w(...P)e..P;..r..0.t0.u.,~..v.,lIw;..1.v.){.i(.!..D).b;..'.P='.D.o.i(.-.>....j....IUx..y[.za.A..N8.B.=..C.C .UzN.D..A..y~..:...NC2<..y3.N....}.a....e{2.g.$. ...=.v.[.A{.D..d @@ -27,6 +26,9 @@ Z....&.;2 .i.*...F*.*I.G..H..hrJ..K.........#.].....?rycoun.Qy.8"..tM.=Iq..n.. .nex..seq.Len.....T.qC.==.f(..=..;R..<....Pu.....=IL...u,..[z..]Z.K.,@....s..c..rMG.-....y.|..E..-7.r.%.]..qe$...W.mQ00.E.:.%.as..J..I........!r.r.r..r.r.r .1....ma.i..?.?.*..=@rA.4.DL.[C5.T.T...lINp.ti.ck~.le# .!.7. g..v.O*..Q......+./.z./._ 7_..../.. 6..c./.. 5 ..........Z.. ..7.........lIS:..L^.Premp<..to 6pl.......a$cVO.}.,=.c...[C8n...SD...%s .@........f.bf.f.f.f.A/.Nj.j...c.......WebTV...8....0.Wai.A...+.1...a.IS..n.swee.].=.\....-...M.....V -O.(..(...yI. ....v..4.4....*....rn...k@..L(..T..U...IV..r..Sw.tv_6......S.....base.ts.f .. 77 (.ANI=(E.et;))^Eani.X..0.P.E..ldIl.....k..W....5...'......O...#.*.vi.c..9=39==s33.` -.<32...n..Io.di.=SS ....[.`]...>a[.0...@j...)..6..8,.4G.66.V.o@J 7Y.../P,..Y.5w....... -....4..g.....:.*.V.P*...G...5.qh .J..h..4....=..d....;..$.69;....;.>J...Y...J. 1a.v.:A....._...q:.Q.6;..o.5.Y.Q...h.......?.a...<......Z.." h. "+..U..{.....l..,s?..r;..1C.47..7.... .\.. .zb~!..P.8.i..P.X)....Y......,*IZ@.*Ia9c. ..lIy.q...(.=S18006.13819..6.=;Sa .mis..6..@...:.:.:.H.8.w..BUGd.....a1.....`.....i.........,..B...c.\.b...c..d..$.fcJ..g0.h..=.@,.U@-.@..@/.@0...BW.A.*C64..+P.I1..`...o.U....u.... for~..%d:%02...........l..p..r.;.S.S1. |.D.@S.D...e...e.\.\.\..\.L.A.......>.".^...S-a*.-...,..(...\.....;.#..o..t10..L0o..u1.d.<.J.m.i.j.S.-..-.1I...t.s...a...`..o.)....e.......,1.]...!..*...]...%.br..&! P.#. =y#mQ. x....."..Y...... ..........T..).,`+..r1.ZyS.{A.,se..tsf /4 7.7 (ANI=(...et)).uan.i..w.+.#.....I)l....k_.Z..g................n{amt.rvic...9=39==33\o. +.<32..na..IoA.i.=S |....[C6.]...0..9.....p. ).NN.=C6..G.5G....V.{.....7e.6Jt.8t.4J...j.. +.u.f. +.W.4..9....+...8...*...5RK.h ...h..; +..1..6....=C5 9-...6..3...K.U=^.4..;..:[..&.w.....3.w..@o..:.o.I.:..~......,.o.,.........~.I5....>....?...;.Q.{.ev..nlIUa..b..c..d...f..b..g.....!r. +r..y.........O.~........ \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/LC2/artemis_18004653537.tok b/hacktv_updsrv/ServiceDeps/LC2/artemis_18004653537.tok similarity index 100% rename from hacktv_updsrv/ServiceVault/wtv-1800/LC2/artemis_18004653537.tok rename to hacktv_updsrv/ServiceDeps/LC2/artemis_18004653537.tok diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/LC2/artemis_18006138199.tok b/hacktv_updsrv/ServiceDeps/LC2/artemis_18006138199.tok similarity index 100% rename from hacktv_updsrv/ServiceVault/wtv-1800/LC2/artemis_18006138199.tok rename to hacktv_updsrv/ServiceDeps/LC2/artemis_18006138199.tok diff --git a/hacktv_updsrv/ServiceDeps/splash.html b/hacktv_updsrv/ServiceDeps/splash.html new file mode 100644 index 00000000..0c7ebd70 --- /dev/null +++ b/hacktv_updsrv/ServiceDeps/splash.html @@ -0,0 +1,21 @@ + + + + + + + + + +
+ +
+ +


+


+


+ + +

+ + diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/mame.jpg b/hacktv_updsrv/ServiceVault/wtv-1800/mame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2c3bdc9dcb4200ac300616d31f37198531b94696 GIT binary patch literal 13922 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 QU-ayM)NSYu=6Ugd0avS9v;Y7A literal 0 HcmV?d00001 diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/offer-open-isp-suggest.js b/hacktv_updsrv/ServiceVault/wtv-1800/offer-open-isp-suggest.js index 1d44c1be..aa7738c4 100644 --- a/hacktv_updsrv/ServiceVault/wtv-1800/offer-open-isp-suggest.js +++ b/hacktv_updsrv/ServiceVault/wtv-1800/offer-open-isp-suggest.js @@ -1,29 +1,30 @@ -var ssid = initial_headers['wtv-client-serial-number'] || null; -if (ssid != null && !sec_session[ssid]) { - sec_session[ssid] = new WTVNetworkSecurity(); - sec_session[ssid].IssueChallenge(); +if (socket_session_data[socket.id].ssid != null && !sec_session[socket_session_data[socket.id].ssid]) { + sec_session[socket_session_data[socket.id].ssid] = new WTVNetworkSecurity(); + sec_session[socket_session_data[socket.id].ssid].IssueChallenge(); + sec_session[socket_session_data[socket.id].ssid].set_incarnation(initial_headers['wtv-incarnation']); } headers = `200 OK -Connection: Keep-Alive +Connection: Close +wtv-initial-key: ` + sec_session[socket_session_data[socket.id].ssid].challenge_key.toString(CryptoJS.enc.Base64) + ` Content-Type: text/tellyscript -wtv-initial-key: ` + sec_session[ssid].challenge_key.toString(CryptoJS.enc.Base64) + ` wtv-service: reset wtv-service: name=wtv-1800 host=` + pubip + ` port=1615 connections=1 wtv-service: name=wtv-head-waiter host=` + pubip + ` port=1615 flags=0x04 flags=0x00000001 connections=1 wtv-service: name=htv-update host=` + pubip + ` port=1615 flags=0x04 -wtv-client-time-zone: GMT -0000 -wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT wtv-boot-url: wtv-head-waiter:/login? -Location: wtv-head-waiter:/login? -wtv-visit: wtv-head-waiter:/login?`; +wtv-visit: wtv-head-waiter:/login? +wtv-client-time-zone: GMT -0000 +wtv-client-time-dst-rule: GMT +wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT`; -var romtype = getWTVROMType(initial_headers); +var romtype = socket_session_data[socket.id].romtype; switch (romtype) { case "US-LC2-disk-0MB-8MB": - data = fs.readFileSync(__dirname + "/ServiceVault/wtv-1800/LC2/artemis_18006138199.tok"); + data = fs.readFileSync(__dirname + "/ServiceDeps/LC2/artemis_18006138199.tok").buffer; + //data = fs.readFileSync(__dirname + "/ServiceDeps/LC2/LC2.tok").buffer; break; default: diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/preregister.js b/hacktv_updsrv/ServiceVault/wtv-1800/preregister.js index c5eb2007..10f048f6 100644 --- a/hacktv_updsrv/ServiceVault/wtv-1800/preregister.js +++ b/hacktv_updsrv/ServiceVault/wtv-1800/preregister.js @@ -1,4 +1,5 @@ headers = `200 OK Connection: Keep-Alive wtv-open-isp-disabled: false -wtv-visit: wtv-1800:/offer-open-isp-suggest?`; \ No newline at end of file +wtv-visit: wtv-1800:/offer-open-isp-suggest? +Content-type: text/html`; \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js index e9f51832..afef9f9c 100644 --- a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js +++ b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js @@ -1,17 +1,45 @@ -var ssid = initial_headers['wtv-client-serial-number'] || null; -var initialChallenge, challenge_response, challenge_header = ''; +var challenge_response, challenge_header = ''; +var gourl; -if (ssid !== null) { - if (sec_session[ssid].ticket) { - challenge_header = "wtv-ticket: "+sec_session[ssid].ticket; +if (socket_session_data[socket.id].ssid !== null) { + if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) { + if (initial_headers['wtv-ticket']) { + if (initial_headers['wtv-ticket'].length > 8) { + DecodeTicket(initial_headers['wtv-ticket']); + sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket']; + socket_session_data[socket.id].secure == true; + } + } else { + challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response; + var client_challenge_response = initial_headers['wtv-challenge-response'] || null; + if (challenge_response && client_challenge_response) { + if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) { + console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid); + sec_session[socket_session_data[socket.id].ssid].PrepareTicket(); + socket_session_data[socket.id].secure == true; + } else { + gourl = "wtv-head-waiter:/login?reissue_challenge=true"; + } + } else { + gourl = "wtv-head-waiter:/login?no_response=true"; + } + } } } - - - +if (gourl) { headers = `200 OK -wtv-ticket: `+sec_session[ssid].ticket+` +Connection: Keep-Alive +wtv-open-isp-disabled: false +wtv-visit: `+gourl+` +Content-type: text/html`; + data = ''; +} else { + headers = `200 OK +Connection: Keep-Alive +wtv-encrypted: true +wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+` Content-Type: text/html`; - -data = sec_session[ssid].EncryptKey1('hehe! stage two! and its encrypted!'); \ No newline at end of file + + data = "hehe! stage two! test"; +} \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js index bdee70b9..db8cb13b 100644 --- a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js +++ b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js @@ -1,43 +1,63 @@ -var ssid = initial_headers['wtv-client-serial-number'] || null; var initialChallenge, challenge_response, challenge_header = ''; -var gourl = "wtv-head-waiter:/login?reissue_challenge=true"; +var gourl = "wtv-head-waiter:/login-stage-two?"; -if (query['reissue_challenge']) { - gourl = "client:activ"; -} -if (ssid !== null) { - if (sec_session[ssid].ticket_b64 == null) { +if (socket_session_data[socket.id].ssid !== null) { + if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) { if (initial_headers['wtv-ticket']) { - DecodeTicket(initial_headers['wtv-ticket']); - sec_session[ssid].ticket_b64 = initial_headers['wtv-ticket']; - challenge_header = "wtv-ticket: "+initial_headers['wtv-ticket']; + if (initial_headers['wtv-ticket'].length > 8) { + DecodeTicket(initial_headers['wtv-ticket']); + sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket']; + } } else { - challenge_response = sec_session[ssid].challenge_response; + challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response; var client_challenge_response = initial_headers['wtv-challenge-response'] || null; if (challenge_response && client_challenge_response) { if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) { - console.log(" * wtv-challenge-response success for "+ssid); - sec_session[ssid].PrepareTicket(); - challenge_header = "wtv-ticket: "+sec_session[ssid].ticket_b64; - var gourl = "wtv-head-waiter:/login-stage-two?"; + console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid); + sec_session[socket_session_data[socket.id].ssid].PrepareTicket(); } else { - challenge_header = "wtv-whatever: meh"; - gourl = "wtv-1800:/preregister?"; + challenge_header = "wtv-challenge: "+sec_session[socket_session_data[socket.id].ssid].IssueChallenge(); } } else { - if (sec_session[ssid].challenge_b64 == null) { - challenge_header = "wtv-whatever: meh"; - gourl = "wtv-1800:/preregister?"; - } else { - challenge_header = "wtv-challenge: "+sec_session[ssid].challenge_b64; - } + challenge_header = "wtv-challenge: "+sec_session[socket_session_data[socket.id].ssid].IssueChallenge(); } } - } else { - challenge_header = "wtv-ticket: "+sec_session[ssid].ticket_b64; } } - + +if (sec_session[socket_session_data[socket.id].ssid].ticket_b64) { + headers = `200 OK +Connection: Keep-Alive +wtv-encrypted: true +wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+` +wtv-client-time-zone: GMT -0000 +wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT +wtv-country: US +wtv-language-header: en-US,en +wtv-visit: client:closeallpanels +wtv-expire-all: client:closeallpanels +wtv-noback-all: wtv- +wtv-service: reset +wtv-service: name=wtv-1800 host=` + pubip + ` port=1615 connections=1 +wtv-service: name=wtv-head-waiter host=` + pubip + ` port=1615 flags=0x04 flags=0x00000001 connections=1 +wtv-service: name=htv-update host=` + pubip + ` port=1615 flags=0x04 +wtv-boot-url: wtv-head-waiter:/login? +wtv-input-timeout: 14400 +wtv-connection-timeout: 90 +wtv-fader-timeout: 900 +wtv-ssl-log-url: wtv-log:/log +wtv-bypass-proxy: true +wtv-allow-dsc: true +wtv-messenger-enable: 0 +wtv-nameserver: 1.1.1.1 +wtv-phone-log-url: wtv-log:/log +wtv-visit: wtv-head-waiter:/login-stage-two? +Content-type: text/html` + +data = ''; +//data = fs.readFileSync(__dirname + "/ServiceDeps/splash.html"); + +} else { headers = `200 OK Connection: Keep-Alive @@ -49,9 +69,6 @@ wtv-log-url: wtv-log:/log wtv-relogin-url: wtv-1800:/preregister?relogin=true wtv-reconnect-url: wtv-1800:/preregister?reconnect=true wtv-visit: `+gourl+` -Content-length: 0 Content-type: text/html`; - data = ''; - - +} \ No newline at end of file diff --git a/hacktv_updsrv/app.js b/hacktv_updsrv/app.js index fdeefb09..e21f5ff6 100644 --- a/hacktv_updsrv/app.js +++ b/hacktv_updsrv/app.js @@ -7,45 +7,17 @@ const strftime = require('strftime'); const net = require('net'); const CryptoJS = require('crypto-js'); const mime = require('mime-types'); +var str2ab = require('string-to-arraybuffer') var WTVNetworkSecurity = require('./wtvsec.js'); var zdebug = true; +var secure_mode = true; var pubip = "192.168.11.8"; var port = 1615; var sec_session = new Array(); - -function getWTVIncarnation(headers, ssid = null) { - var incarnation = null; - headers.some(function (v) { - if (v.substring(0, 15) === "wtv-incarnation") { - incarnation = v.split(': ')[1].replace("\r", ""); - return incarnation != null; - } - }); - if (ssid != null && incarnation != null) { - if (sec_session[ssid] != null) { - sec_session[ssid].set_incarnation(incarnation); - if (zdebug) console.log(" * Updated wtv-incarnation for " + ssid + " to " + incarnation + " ..."); - } - } - return incarnation; -} - -function getWTVROMType(headers, ssid = null) { - var romtype = null; - headers.some(function (v) { - if (v.substring(0, 19) === "wtv-client-rom-type") { - romtype = v.split(': ')[1].replace("\r", ""); - return romtype != null; - } - }); - return romtype; -} - - - +var socket_session_data = new Array(); function getPublicIP() { var options = { @@ -71,12 +43,14 @@ function doErrorPage(code) { headers = "HTTP/1.1 404 Not Found\r\n"; headers += "Content-Type: text/html\r\n"; break; - case 500: + case 400: data = "An internal server error has occured."; - headers = "HTTP/1.1 500 HackTV has ran into a technical problem.\r\n"; + headers = "400 HackTV ran into a technical problem.\r\n"; headers += "Content-Type: text/html\r\n"; break; default: + // what we send when we did not detect a wtv-url. + // e.g. when a pc browser connects data = "Hello, stranger!"; headers = "HTTP/1.1 200 OK\r\n"; headers += "Content-Type: text/html\r\n"; @@ -85,7 +59,7 @@ function doErrorPage(code) { return new Array(headers, data); } -function processPath(path, initial_headers = new Array(), query = new Array()) { +function processPath(socket, path, initial_headers = new Array(), query = new Array()) { var headers, data = null; var request_is_direct_file = false; try { @@ -100,29 +74,29 @@ function processPath(path, initial_headers = new Array(), query = new Array()) { if (request_is_direct_file) { // file exists, read it and return it - console.log(" * Found " + path + " to handle request"); + console.log(" * Found " + path + " to handle request (Direct File Mode)"); var contype = mime.lookup(path); - data = fs.readFileSync(path); - headers = "200 OK\r\n" + data = fs.readFileSync(path).buffer; + headers = "200 OK\n" headers += "Content-Type: " + contype; } else if (fs.existsSync(path + ".txt")) { // raw text format, entire payload expected (headers and content) - console.log(" * Found " + path + ".txt to handle request"); + console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode)"); var fdat = fs.readFileSync(path + ".txt").toString(); - headers = fdat.split("\r\n\r\n")[0]; - data = fdat.split("\r\n\r\n")[1]; + headers = fdat.split("\n\n")[0]; + data = fdat.split("\n\n")[1]; } else if (fs.existsSync(path + ".js")) { // js scripting, process with vars, must set 'headers' and 'data' appropriately. // loaded script will have r/w access to any JavaScript vars this function does. // any query args are in an array named 'query' - console.log(" * Found " + path + ".js to handle request"); + console.log(" * Found " + path + ".js to handle request (JS Interpreter mode)"); var fdat = fs.readFileSync(path + ".js").toString(); eval(fdat); } else if (fs.existsSync(path + ".html")) { // Standard HTML with no headers, WTV Style - console.log(" * Found " + path + ".html to handle request"); + console.log(" * Found " + path + ".html to handle request (HTML Mode)"); data = fs.readFileSync(path + ".html").toString(); - headers = "200 OK\r\n" + headers = "200 OK\n" headers += "Content-Type: text/html" } else { var errpage = doErrorPage(404); @@ -137,123 +111,289 @@ function processPath(path, initial_headers = new Array(), query = new Array()) { if (typeof headers !== "string") { headers = headers.toString(); } - if (headers.indexOf("\r") === -1) { - headers = headers.replace("\n", "\r\n"); - } } else { - var errpage = doErrorPage(500); + var errpage = doErrorPage(400); headers = errpage[0]; data = errpage[1]; } if (data === null) { data = ''; } - if (typeof data !== "string") { - data = data.toString(); - } } catch (e) { - var errpage = doErrorPage(500); + var errpage = doErrorPage(400); headers = errpage[0]; - data = errpage[1] + "

" + e.toString() + "
"; + data = errpage[1] + "

The interpreter said:
" + e.toString() + "
"; console.log(e); } if (headers.toLowerCase().indexOf("content-length") === -1) { - headers += "\r\nContent-Length: " + data.length; + if (typeof data.length !== 'undefined') { + headers += "\nContent-Length: " + data.length; + } else if (typeof data.byteLength !== 'undefined') { + headers += "\nContent-Length: " + data.byteLength; + } } return new Array(headers, data); } -function processURL(initial_headers, socket) { +function processURL(socket, initial_headers) { + if (initial_headers === null) { + return; + } var shortURL, headers, data = ""; var query = new Array(); - if (initial_headers['request_url'].indexOf('?') >= 0) { - shortURL = initial_headers['request_url'].split('?')[0]; - var qraw = initial_headers['request_url'].split('?')[1]; - if (qraw.length > 0) { - qraw = qraw.split("&"); - for (let i = 0; i < qraw.length; i++) { - query[qraw[i].split("=")[0]] = qraw[i].split("=")[1]; + if (initial_headers['request_url']) { + if (initial_headers['request_url'].indexOf('?') >= 0) { + shortURL = initial_headers['request_url'].split('?')[0]; + var qraw = initial_headers['request_url'].split('?')[1]; + if (qraw.length > 0) { + qraw = qraw.split("&"); + for (let i = 0; i < qraw.length; i++) { + query[qraw[i].split("=")[0]] = qraw[i].split("=")[1]; + } + if (zdebug) { + console.log("URL Request has query arguments:") + console.log(query); + } } - if (zdebug) { - console.log("URL Request has query arguments:") - console.log(query); + } else { + shortURL = initial_headers['request_url']; + } + + if (shortURL.indexOf(':/') >= 0) { + var ssid = socket_session_data[socket.id].ssid; + if (ssid == null) { + ssid = initial_headers['wtv-client-serial-number']; } - } - } else { - shortURL = initial_headers['request_url']; - } + if (ssid != null) { + console.log(" * Request for " + initial_headers['request_url'] + " from WebTV SSID " + ssid); + } else { + console.log(" * Request for " + initial_headers['request_url']); + } + // assume webtv since there is a :/ in the GET + var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1]; + if (zdebug) console.log(initial_headers); + var result = processPath(socket, urlToPath, initial_headers, query); - if (shortURL.indexOf(':/') >= 0) { - var ssid = initial_headers['wtv-client-serial-number']; - if (ssid != null) { - console.log(" * Request for " + initial_headers['request_url'] + " from WebTV SSID " + ssid); - } else { - console.log(" * Request for " + initial_headers['request_url']); - } - // assume webtv since there is a :/ in the GET - var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1]; - if (zdebug) console.log(initial_headers); - var result = processPath(urlToPath, initial_headers, query); - - if (result[0] == null) { - var errpage = doErrorPage(404); - headers = errpage[0]; - data = errpage[1]; - } else { - headers = result[0]; - data = result[1]; - } - } else { - switch (shortURL) { - default: - var errpage = doErrorPage(200); + if (result[0] == null) { + var errpage = doErrorPage(404); headers = errpage[0]; data = errpage[1]; - break; + } else { + headers = result[0]; + data = result[1]; + } + } else { + switch (shortURL) { + default: + var errpage = doErrorPage(200); + headers = errpage[0]; + data = errpage[1]; + break; + } } + } else { + var errpage = doErrorPage(400); + headers = errpage[0]; + data = errpage[1]; } + // headers to object + if (typeof headers != 'object') { + var headers_obj = {}; + var inc_headers = 1; + headers.split('\n').forEach(function (d) { + if (d.length > 0) { + if (d.indexOf(":") > 0 && !/^([0-9]{3} )/.test(d.substring(0, 4))) { + var d = d.split(':'); + var header_name = d[0]; + d.shift(); + if (headers_obj[header_name] != null) { + header_name = header_name + "_" + inc_headers; + inc_headers++; + } + headers_obj[header_name] = d.join(':').replace("\r", ""); + if (headers_obj[header_name].substring(0, 1) == " ") { + headers_obj[header_name] = headers_obj[header_name].substring(1); + } + } else if (/^([0-9]{3} )/.test(d.substring(0, 4))) { + headers_obj['http_response'] = d.replace("\r", ""); + } + } + }); + } else { + header_obj = headers; + } - var toClient = headers + "\r\n\r\n" + data; - console.log(headers); - socket.write(toClient); - socket.destroy(); + // set wtv-encrypted and put it near the top of the headers (unknown if needed) + if (socket_session_data[socket.id].secure == true) { + console.log(" * encrypting response to client ...") + headers_obj['wtv-encrypted'] = true; + headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj); + var enc_data = sec_session[socket_session_data[socket.id].ssid].EncryptKey2(data); + var test = data; + } + + headers = ""; + console.log(headers_obj); + Object.keys(headers_obj).forEach(function (k) { + if (k == "http_response") { + headers += headers_obj[k] + "\r\n"; + } else { + if (k.indexOf('_') >= 0) { + var j = k.split('_')[0]; + headers += j + ": " + headers_obj[k] + "\n"; + } else { + headers += k + ": " + headers_obj[k] + "\n"; + } + } + }); + var toClient = null; + if (typeof data == 'string') { + toClient = headers + "\n" + data; + socket.write(toClient); + } else if (typeof data == 'object') { + socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\r\n"), data))); + } + if (headers_obj['Connection']) { + if (headers_obj['Connection'].toLowerCase() == "close") { + socket.destroy(); + } + } + } +function concatArrayBuffer(buffer1, buffer2) { + var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(new Uint8Array(buffer1), 0); + tmp.set(new Uint8Array(buffer2), buffer1.byteLength); + return tmp.buffer; +} -var server = net.createServer(function (socket) { - socket.setEncoding("utf8"); //set data encoding (either 'ascii', 'utf8', or 'base64') +function moveObjectElement(currentKey, afterKey, obj) { + var result = {}; + var val = obj[currentKey]; + delete obj[currentKey]; + var next = -1; + var i = 0; + if (typeof afterKey == 'undefined' || afterKey == null) afterKey = ''; + Object.keys(obj).forEach(function (k) { + var v = obj[k]; + if ((afterKey == '' && i == 0) || next == 1) { + result[currentKey] = val; + next = 0; + } + if (k == afterKey) { next = 1; } + result[k] = v; + ++i; + }); + if (next == 1) { + result[currentKey] = val; + } + if (next !== -1) return result; else return obj; +} - socket.on('data', function (data) { - var url = ""; - var headers = new Array(); - if (typeof data === "string") { - data.split('\n').forEach(function (d) { - if (d != "") { - if (d == "SECURE ON") { - headers['secure'] = true; - } - if (d.indexOf(": ") > 0) { - headers[d.split(': ')[0]] = (d.split(': ')[1]).replace("\r",""); - } else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4))) { - headers['request'] = d.replace("\r", ""); - headers['request_url'] = (d.split(' ')[1]).replace("\r", ""); +function headersAreStandard(string) { + // the test will see the binary compressed/enrypted data as ASCII, so a generic "isAscii" + // is not suffuicent. This checks for characters expected in unecrypted headers, and returns + // true only if every character in the string matches the regex. Once we know the string is binary + // we can better process it with the raw base64 data in processHeaders() below. + var test = /^([A-Za-z0-9\+\/\=\-\.\ \;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string); + if (zdebug) console.log("request is ascii: " + test); + if (zdebug) console.log("request as follows: " + string); + return test; + } + +function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) { + var url = ""; + var data = CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Base64.parse(data_b64)); + + var headers = new Array(); + if (typeof data === "string") { + if (data.length > 1) { + if (headersAreStandard(data)) { + data = data.split("\r\n\r\n")[0]; + data.split('\n').forEach(function (d) { + if (d.length > 0) { + if (/^SECURE ON/.test(d)) { + console.log(data); + secure_mode = true; + headers['secure'] = true; + socket_session_data[socket.id].secure = true; + } + if (d.indexOf(":") > 0 && d.indexOf(":/") == -1) { + headers[d.split(':')[0]] = (d.split(':')[1]).replace("\r", ""); + if (headers[d.split(':')[0]].substring(0, 1) == " ") { + headers[d.split(':')[0]] = headers[d.split(':')[0]].substring(1); + } + } else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4))) { + headers['request'] = d.replace("\r", ""); + headers['request_url'] = (d.split(' ')[1]).replace("\r", ""); + } } + }); + } else { + // failed the headersAreStandard test, so we think this is a binary blob + var encdata = CryptoJS.enc.Base64.parse(data_b64); + var decdata = sec_session[socket_session_data[socket.id].ssid].DecryptKey1(encdata); + var test = decdata; + } + if (headers['wtv-client-rom-type'] != null) { + socket_session_data[socket.id].romtype = headers['wtv-client-rom-type']; + } + if (headers['wtv-client-serial-number'] != null) { + socket_session_data[socket.id].ssid = headers['wtv-client-serial-number']; + } + if (headers['wtv-incarnation'] != null) { + if (sec_session[socket_session_data[socket.id].ssid]) { + sec_session[socket_session_data[socket.id].ssid].set_incarnation(headers['wtv-incarnation']); } - }); - console.log(headers); + } + + if (returnHeadersBeforeSecure) { + return headers; + } + if (headers['secure'] === true) { // assume we have an ssid if we are this far sec_session[headers['wtv-client-serial-number']].SecureOn(); if (!headers['request_url']) { - headers['request_url'] = "wtv-head-waiter:/login-stage-two?"; + var header_length = data.length + 4; + var enc_data = CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse(data_b64).toString(CryptoJS.enc.Hex).substring(header_length * 2)); + console.log(enc_data.toString(CryptoJS.enc.Hex)); + if (enc_data.sigBytes > 0) { + var dec_data = sec_session[socket_session_data[socket.id].ssid].DecryptKey1(enc_data); + console.log(dec_data); + console.log(headers); + } } } - - processURL(headers,this); + return headers; + } else { + // socket error, terminate it. + socket.destroy(); } + } + return null; +} + +var server = net.createServer(function (socket) { + socket.binaryType = 'arraybuffer'; + socket.id = Math.floor(Math.random() * 1000); + socket_session_data[socket.id] = []; + socket.setEncoding('base64'); //set data encoding (either 'ascii', 'utf8', or 'base64') + + socket.on('data', function (data_b64) { + processURL(this, processHeaders(this, data_b64)); }); + socket.on('error', (err, socket) => { + console.log('client socket error:', err); + }); + + socket.on('end', function () { + secure_mode = false; + socket_session_data[socket.id] = null; + }); }); server.listen(port, '0.0.0.0'); diff --git a/hacktv_updsrv/package-lock.json b/hacktv_updsrv/package-lock.json index ec3f2423..2684127c 100644 --- a/hacktv_updsrv/package-lock.json +++ b/hacktv_updsrv/package-lock.json @@ -4,23 +4,25 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "arc4": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/arc4/-/arc4-3.4.0.tgz", - "integrity": "sha512-zFQmSbTwSTrICYV8kldrD3YreCtlLIKEZk+lmlNSlpUKU/cF9o746WFEy9eNqLrqSyUgAAjB3gnD9UXdK23beA==", - "requires": { - "lodash": "4.17.4" - } + "atob-lite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", + "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=" }, "crypto-js": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + "endianness": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/endianness/-/endianness-8.0.2.tgz", + "integrity": "sha512-IU+77+jJ7lpw2qZ3NUuqBZFy3GuioNgXUdsL1L9tooDNTaw0TgOnwNuc+8Ns+haDaTifK97QLzmOANJtI/rGvw==" + }, + "is-base64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-base64/-/is-base64-0.1.0.tgz", + "integrity": "sha512-WRRyllsGXJM7ZN7gPTCCQ/6wNPTRDwiWdPK66l5sJzcU/oOzcIcRRf0Rux8bkpox/1yjt0F6VJRsQOIG2qz5sg==" }, "mime-db": { "version": "1.48.0", @@ -39,6 +41,15 @@ "version": "0.10.0", "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.0.tgz", "integrity": "sha1-s/D6QZKVICpaKJ9ta+n0kJphcZM=" + }, + "string-to-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-to-arraybuffer/-/string-to-arraybuffer-1.0.2.tgz", + "integrity": "sha512-DaGZidzi93dwjQen5I2osxR9ERS/R7B1PFyufNMnzhj+fmlDQAc1DSDIJVJhgI8Oq221efIMbABUBdPHDRt43Q==", + "requires": { + "atob-lite": "^2.0.0", + "is-base64": "^0.1.0" + } } } } diff --git a/hacktv_updsrv/package.json b/hacktv_updsrv/package.json index 70fdcb52..adc4c846 100644 --- a/hacktv_updsrv/package.json +++ b/hacktv_updsrv/package.json @@ -7,9 +7,10 @@ "name": "" }, "dependencies": { - "arc4": "^3.4.0", "crypto-js": "^4.0.0", + "endianness": "^8.0.2", "mime-types": "^2.1.31", - "strftime": "^0.10.0" + "strftime": "^0.10.0", + "string-to-arraybuffer": "^1.0.2" } } diff --git a/hacktv_updsrv/wtvsec.js b/hacktv_updsrv/wtvsec.js index 9df6d79d..74597edc 100644 --- a/hacktv_updsrv/wtvsec.js +++ b/hacktv_updsrv/wtvsec.js @@ -1,19 +1,18 @@ const CryptoJS = require('crypto-js'); -const rc4 = require('arc4'); +const endianness = require('endianness'); class WTVNetworkSecurity { initial_shared_key = null; current_shared_key = null; challenge_key = null; challenge_response = null; - challenge_b64 = null; ticket_b64 = null; incarnation = 1; session_key1 = null; session_key2 = null; hRC4_Key1 = null; hRC4_Key2 = null; - zdebug = false; + zdebug = true; constructor(wtv_initial_key = CryptoJS.lib.WordArray.random(8), wtv_incarnation = 1) { var initial_key = wtv_initial_key; @@ -31,6 +30,7 @@ class WTVNetworkSecurity { set_incarnation(wtv_incarnation) { this.incarnation = wtv_incarnation; + this.SecureOn(); } increment_incarnation() { @@ -45,11 +45,12 @@ class WTVNetworkSecurity { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); - this.ticket_b64 = this.current_shared_key.concat(ticket_data_enc.ciphertext.toString(CryptoJS.enc.Base64)); + this.ticket_b64 = this.current_shared_key.concat(ticket_data_enc.ciphertext).toString(CryptoJS.enc.Base64); } catch (e) { console.log("Error encrypting ticket: " + e.toString()); return null; } + return this.ticket_b64; } DecodeTicket(ticket_b64) { @@ -156,22 +157,54 @@ class WTVNetworkSecurity { // get the expected response for when client sends it this.challenge_response = this.ProcessChallenge(challenge_b64); this.challenge_key = this.current_shared_key; - this.challenge_b64 = challenge_b64; this.current_shared_key = new_shared_key; return challenge_b64; } - SecureOn() { - var buf = Buffer.allocUnsafe(4); - buf.writeUIntLE(this.incarnation, 0, 4); - var bigbuf = buf.readUIntBE(0, 4); - var md5_digest_key1 = CryptoJS.MD5(this.session_key1.concat(CryptoJS.lib.WordArray.create(bigbuf).concat(this.session_key1))); + wordToByteArray(word, length) { + var ba = [], + i, + xFF = 0xFF; + if (length > 0) + ba.push(word >>> 24); + if (length > 1) + ba.push((word >>> 16) & xFF); + if (length > 2) + ba.push((word >>> 8) & xFF); + if (length > 3) + ba.push(word & xFF); - buf = Buffer.allocUnsafe(4); - buf.writeUIntLE(this.incarnation, 0, 4); - bigbuf = buf.readUIntBE(0, 4); - var md5_digest_key2 = CryptoJS.MD5(this.session_key2.concat(CryptoJS.lib.WordArray.create(bigbuf).concat(this.session_key2))); + return ba; + } + + wordArrayToUint8Array(wordArray, length = 0) { + if (wordArray.hasOwnProperty("sigBytes") && wordArray.hasOwnProperty("words")) { + length = wordArray.sigBytes; + wordArray = wordArray.words; + } + + var result = [], + bytes, + i = 0; + while (length > 0) { + bytes = this.wordToByteArray(wordArray[i], Math.min(4, length)); + length -= bytes.length; + result.push(bytes); + i++; + } + return new Uint8Array([].concat.apply([], result)); + } + + SecureOn() { + var buf = new Uint8Array([0xff & this.incarnation, 0xff & (this.incarnation >> 8), 0xff & (this.incarnation >> 16), 0xff & (this.incarnation >> 24)]); + endianness(buf, 2); + var md5_digest_key1 = CryptoJS.MD5(this.session_key1.concat(CryptoJS.lib.WordArray.create(buf).concat(this.session_key1))); + + var next_incarnation = this.incarnation + 1; + buf = new Uint8Array([0xff & next_incarnation, 0xff & (next_incarnation >> 8), 0xff & (next_incarnation >> 16), 0xff & (next_incarnation >> 24)]); + endianness(buf, 2); + var md5_digest_key2 = CryptoJS.MD5(this.session_key2.concat(CryptoJS.lib.WordArray.create(buf).concat(this.session_key2))); this.hRC4_Key1 = md5_digest_key1; @@ -179,34 +212,42 @@ class WTVNetworkSecurity { } EncryptKey1(data) { - return this.Encrypt(this.hRC4_Key1, data); + return Buffer.from(this.wordArrayToUint8Array(this.Encrypt(this.hRC4_Key1, CryptoJS.lib.WordArray.create(data)).ciphertext)); } EncryptKey2(data) { - return this.Encrypt(this.hRC4_Key2, data); + return Buffer.from(this.wordArrayToUint8Array(this.Encrypt(this.hRC4_Key2, CryptoJS.lib.WordArray.create(data)).ciphertext)); } - Encrypt(context, data) { - if (key != null) { - return CryptoJS.RC4.encrypt(data, key); - } else { - throw ("Invalid RC4 encryption key"); + Encrypt(key, data) { + try { + if (key != null) { + return CryptoJS.RC4.encrypt(data, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.NoPadding + }); + } + } catch (e) { + throw ("Invalid RC4 encryption key: " + e.toString()); } } DecryptKey1(data) { - return this.Decrypt(this.hRC4_Key1, data); + return Buffer.from(this.wordArrayToUint8Array(this.Decrypt(this.hRC4_Key1, data))); } DecryptKey2(data) { - return this.Decrypt(this.hRC4_Key2, data); + return Buffer.from(this.wordArrayToUint8Array(this.Decrypt(this.hRC4_Key2, data))); } Decrypt(key, data) { - if (key != null) { - return CryptoJS.RC4.decrypt(data, key); - } else { - throw ("Invalid RC4 encryption key"); + try { + return CryptoJS.RC4.decrypt(data, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.NoPadding + }); + } catch (e) { + throw ("Invalid RC4 encryption key: " + e.toString()); } }