code wiki / (root) / nx_https_get_spoof.nx

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}