nx_https_get_spoof.nx source
↩ module page · 149 lines · 9517 B
1// nx_https_get_spoof.nx -- validated-TLS HTTPS GET that SPOOFS a real browser (X-TORRENT-SPOOF R2):
2// real Firefox UA + browser Accept headers + a Cookie header (the operator's cf_clearance/session read
3// from Waterfox by nx_ff_cookies). This is what gets past a Cloudflare 403 -- the cf_clearance cookie
4// is UA-bound, so we present a Firefox UA to match Waterfox. Reuses nx_https_get's connect+handshake
5// (steps 1-3) verbatim and copies the get_complete round-trip with a spoofed request builder.
6// argv[1]=url argv[2]=cookie ("a=b; c=d", optional) argv[3]=outpath -> writes raw response, prints size+status.
7// license_tier: ORIGINAL module: nishi-core.browser.https_get_spoof
8import "nx_codec_caps.nx"
9import "nx_https_get.nx"
10import "nx_tls13_record.nx"
11import "nx_tls13_read_record_from_fd.nx"
12import "nx_tls13_client_session.nx"
13import "nx_http_client.nx"
14import "nx_x509_trust_store.nx"
15import "nx_pem_loader.nx"
16import "nx_csprng.nx"
17import "nx_url.nx"
18import "nx_syscalls.nx"
19
20func sp_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
21func sp_wn(fd: i64, v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0 {t[0]=48 as u8;k=1} while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(28); var i: i64=0; while i<k {b[i]=t[k-1-i];i=i+1} sys_write(fd,b,k); return 0 }
22func sp_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off+i]=s[i];i=i+1} return off+i }
23
24func _sp_write_n(fd: i64, buf: *u8, n: i64) -> i64 {
25 var off: i64 = 0
26 while off < n { let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off); if w <= 0 { return 0 - 1 } off = off + w }
27 return 0
28}
29
30// real-browser GET request with optional Cookie. identity encoding (we don't gunzip the body here).
31func sp_build(path: *u8, plen: i64, host: *u8, hlen: i64, cookie: *u8, clen: i64, out: *u8) -> i64 {
32 var o: i64 = 0
33 o = sp_puts(out, o, "GET " as *u8)
34 var i: i64 = 0; while i < plen { out[o]=path[i]; o=o+1; i=i+1 }
35 o = sp_puts(out, o, " HTTP/1.1\r\nHost: " as *u8)
36 i = 0; while i < hlen { out[o]=host[i]; o=o+1; i=i+1 }
37 o = sp_puts(out, o, "\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0\r\n" as *u8)
38 // Derived from nx_codec_caps, not hand-written: the old literal claimed
39 // image/avif with no AVIF codec in the tree.
40 let sph: *u8 = sys_mmap(1024)
41 nx_codec_caps_accept_document(sph)
42 o = sp_puts(out, o, "Accept: " as *u8)
43 o = sp_puts(out, o, sph)
44 o = sp_puts(out, o, "\r\n" as *u8)
45 o = sp_puts(out, o, "Accept-Language: en-US,en;q=0.5\r\nAccept-Encoding: " as *u8)
46 nx_codec_caps_accept_encoding(sph)
47 o = sp_puts(out, o, sph)
48 o = sp_puts(out, o, "\r\nUpgrade-Insecure-Requests: 1\r\n" as *u8)
49 if clen > 0 { o = sp_puts(out, o, "Cookie: " as *u8); i = 0; while i < clen { out[o]=cookie[i]; o=o+1; i=i+1 } o = sp_puts(out, o, "\r\n" as *u8) }
50 o = sp_puts(out, o, "Connection: close\r\n\r\n" as *u8)
51 return o
52}
53
54// copy of nx_https_get_complete with the spoofed request builder.
55func sp_get_complete(s: *Tls13ClientSession, fd: i64, path: *u8, path_len: i64, host: *u8, host_len: i64, cookie: *u8, clen: i64, out_buf: *u8, out_cap: i64) -> i64 {
56 if s.state != NX_TLS13_CSESSION_STATE_CONNECTED { return 0 - NX_HTTPS_GC_BAD_STATE }
57 let req: *u8 = sys_mmap(8192)
58 let req_len: i64 = sp_build(path, path_len, host, host_len, cookie, clen, req)
59 if req_len <= 0 { return 0 - NX_HTTPS_GC_BUILD_FAIL }
60 let rec_buf: *u8 = sys_mmap(req_len + 64)
61 let header_out: *u8 = rec_buf
62 let ct_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN
63 let tag_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN + req_len + 1
64 let enc_v: i64 = nx_tls13_record_encrypt_v2(s.cipher_suite, s.client_app_traffic_key, s.client_app_iv, s.client_app_seq, req, req_len, NX_TLS13_CT_APPLICATION_DATA, 0, header_out, ct_out, tag_out)
65 s.client_app_seq = s.client_app_seq + 1
66 if enc_v != NX_TLS13_REC_VERDICT_OK { return 0 - NX_HTTPS_GC_ENCRYPT_FAIL }
67 let total_rec_len: i64 = NX_TLS13_RECORD_HEADER_LEN + req_len + 1 + NX_TLS13_RECORD_TAG_LEN
68 if _sp_write_n(fd, rec_buf, total_rec_len) < 0 { return 0 - NX_HTTPS_GC_WRITE_FAIL }
69 var accumulated: i64 = 0
70 while accumulated < out_cap {
71 let rec_in: *u8 = sys_mmap(NX_HTTPS_GC_RESP_RECORD_BYTES)
72 let rec_in_total: i64 = nx_tls13_read_record_from_fd(fd, rec_in, NX_HTTPS_GC_RESP_RECORD_BYTES)
73 if rec_in_total < 0 {
74 let nv: i64 = 0 - rec_in_total
75 if nv == NX_TLS13_READ_REC_EOF { return accumulated }
76 if nv == NX_TLS13_READ_REC_PAYLOAD_EOF { return accumulated }
77 return 0 - NX_HTTPS_GC_READ_FAIL
78 }
79 let rec_in_header: *u8 = rec_in
80 let rec_in_ct: *u8 = rec_in + NX_TLS13_RECORD_HEADER_LEN
81 let rec_in_ct_len: i64 = rec_in_total - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN
82 let rec_in_tag: *u8 = rec_in + rec_in_total - NX_TLS13_RECORD_TAG_LEN
83 let plaintext: *u8 = sys_mmap(rec_in_ct_len + 16)
84 let pct: *i64 = sys_mmap(16) as *i64; let plen2: *i64 = sys_mmap(16) as *i64
85 let dec_v: i64 = nx_tls13_record_decrypt_v2(s.cipher_suite, s.server_app_traffic_key, s.server_app_iv, s.server_app_seq, rec_in_header, rec_in_ct, rec_in_ct_len, rec_in_tag, plaintext, pct, plen2)
86 s.server_app_seq = s.server_app_seq + 1
87 if dec_v != NX_TLS13_REC_VERDICT_OK { return 0 - NX_HTTPS_GC_DECRYPT_FAIL }
88 if pct[0] == NX_TLS13_CT_ALERT { return accumulated }
89 if pct[0] == NX_TLS13_CT_APPLICATION_DATA {
90 let avail: i64 = out_cap - accumulated; let to_copy: i64 = plen2[0]
91 if to_copy > avail { return 0 - NX_HTTPS_GC_BUF_OVERFLOW }
92 var i: i64 = 0; while i < to_copy { out_buf[accumulated+i] = plaintext[i]; i = i + 1 }
93 accumulated = accumulated + to_copy
94 }
95 }
96 return accumulated
97}
98
99// spoofed HTTPS GET: steps 1-3 reuse nx_https_get's flow; step 4 = sp_get_complete.
100func nx_https_get_spoof(url_str: *u8, client_random: *u8, x25519_priv: *u8, store: *TrustStore, now_epoch_secs: i64, cookie: *u8, clen: i64, out_buf: *u8, out_cap: i64) -> i64 {
101 let url_p: *NxUrl = nx_url_new()
102 let target_raw: *u8 = sys_mmap(32); let target: *NxHttpsTarget = target_raw as *NxHttpsTarget
103 target.url = url_p; target.port = 0
104 if nx_https_url_for_fetch(url_str, target) != NX_HTTPS_URL_OK { return 0 - NX_HTTPS_GET_BAD_URL }
105 let fd_p: *i64 = sys_mmap(16) as *i64
106 if nx_https_url_connect(target, url_str, now_epoch_secs, fd_p) != NX_HTTPS_CONNECT_OK { return 0 - NX_HTTPS_GET_CONNECT_FAIL }
107 let fd: i64 = *fd_p
108 let val_ctx_raw: *u8 = sys_mmap(64); let val_ctx: *TlsValidationContext = val_ctx_raw as *TlsValidationContext
109 val_ctx.store = store; val_ctx.sni_host = url_str + target.url.host_off; val_ctx.sni_host_len = target.url.host_len; val_ctx.now_epoch = now_epoch_secs
110 let session_r: i64 = nx_tls13_client_session_run(fd, url_str + target.url.host_off, target.url.host_len, client_random, x25519_priv, val_ctx)
111 if session_r < 0 { sys_close(fd); return 0 - NX_HTTPS_GET_HANDSHAKE_FAIL }
112 let session: *Tls13ClientSession = session_r as *Tls13ClientSession
113 var path_off: i64 = target.url.path_off; var path_len: i64 = target.url.path_len
114 let default_path: *u8 = sys_mmap(2); default_path[0] = 0x2F
115 var path_ptr: *u8 = url_str + path_off
116 if path_len == 0 { path_ptr = default_path; path_len = 1 }
117 if target.url.query_len > 0 {
118 let full: *u8 = sys_mmap(path_len + target.url.query_len + 4); var fo: i64 = 0; var pci: i64 = 0
119 while pci < path_len { full[fo]=path_ptr[pci]; fo=fo+1; pci=pci+1 }
120 full[fo] = 0x3F as u8; fo = fo + 1
121 let qp: *u8 = url_str + target.url.query_off; var qci: i64 = 0
122 while qci < target.url.query_len { full[fo]=qp[qci]; fo=fo+1; qci=qci+1 }
123 path_ptr = full; path_len = fo
124 }
125 let n: i64 = sp_get_complete(session, fd, path_ptr, path_len, url_str + target.url.host_off, target.url.host_len, cookie, clen, out_buf, out_cap)
126 sys_close(fd)
127 return n
128}
129
130func sp_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
131
132func main(argc: i64, argv: *i64) -> i64 {
133 var url: *u8 = "https://example.com/" as *u8
134 if argc >= 2 { url = argv[1] as *u8 }
135 var cookie: *u8 = "" as *u8; var clen: i64 = 0
136 if argc >= 3 { cookie = argv[2] as *u8; clen = sp_strlen(cookie) }
137 var outpath: *u8 = "/mnt/c/Users/elder/Downloads/nishi-torrents/_spoof.html" as *u8
138 if argc >= 4 { outpath = argv[3] as *u8 }
139 let store: *TrustStore = trust_store_alloc(400)
140 if nx_pem_trust_load_file("/etc/ssl/certs/ca-certificates.crt\x00", store) <= 0 { sp_w(1, "no-ca\n" as *u8); sys_exit(1); return 1 }
141 let cr: *u8 = sys_mmap(32); let pk: *u8 = sys_mmap(32); nx_csprng_fill(cr, 32); nx_csprng_fill(pk, 32)
142 let cap: i64 = 2097152; let resp: *u8 = sys_mmap(cap)
143 let n: i64 = nx_https_get_spoof(url, cr, pk, store, sys_now_realtime_sec(), cookie, clen, resp, cap)
144 sp_w(1, "SPOOF-GET n=" as *u8); sp_wn(1, n); sp_w(1, " status='" as *u8)
145 if n > 12 { var i: i64=9; while i<15 { if i<n { sys_write(1, (resp as i64 + i) as *u8, 1) } i=i+1 } } // bytes 9..15 = status code area
146 sp_w(1, "'\n" as *u8)
147 if n > 0 { let fd: i64 = sys_openat_wr(outpath, 0x1a4); if fd>=0 { sys_write(fd, resp, n); sys_close(fd) } }
148 sys_exit(0); return 0
149}