code wiki / _hdl_build / nx_web_harden_gate.nx

nx_web_harden_gate.nx source

↩ module page · 68 lines · 5289 B

1import "nx_gate_base.nx" 2// nx_web_harden_gate.nx -- proves the 90s-neutral neutralizer: the attack teeth are pulled, the page + ads stay. 3import "nx_syscalls.nx" 4import "nx_web_harden.nx" 5 6func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 7" as *u8); return ok } 8func pw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 9func pn(v: i64) -> i64 { let b: *u8=sys_mmap(24); var m: i64=v; if m<0{pw("-" as *u8);m=0-m} let t: *u8=sys_mmap(24); 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} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 10func g_find(hay: *u8, hl: i64, needle: *u8, from: i64) -> i64 { 11 let nl: i64 = g_slen(needle); if nl==0 { return from } 12 var i: i64=from; let last: i64=hl-nl 13 while i<=last { var j: i64=0; var m: i64=1; while j<nl { if (hay[i+j]&0xff)!=(needle[j]&0xff){m=0;j=nl} else {j=j+1} } if m==1 {return i} i=i+1 } 14 return 0-1 15} 16func g_has(hay: *u8, hl: i64, needle: *u8) -> i64 { if g_find(hay,hl,needle,0)>=0 { return 1 } return 0 } 17func g_count_byte(hay: *u8, hl: i64, b: i64) -> i64 { var c: i64=0; var i: i64=0; while i<hl { if (hay[i]&0xff)==b { c=c+1 } i=i+1 } return c } 18// print pass/fail for one check; RETURN ok (0/1) so main can accumulate (module-level mutable globals are not 19// assignable from inside a fn in NishiLang -- keep the tally local to main). 20func chk(label: *u8, ok: i64) -> i64 { 21 if ok==1 { pw(" ok " as *u8) } else { pw(" FAIL " as *u8) } 22 pw(label); pw("\n" as *u8) 23 return ok 24} 25 26func main(argc: i64, argv: *i64) -> i64 { 27 pw("== nx_web_harden_gate ==\n" as *u8) 28 var pass: i64 = 0 29 var total: i64 = 0 30 31 // ---- preamble: the neutralizer JS ---- 32 let pre: *u8 = sys_mmap(16384) 33 let pl: i64 = wh_build_preamble(pre, 16384) 34 pw("preamble bytes: " as *u8); pn(pl); pw("\n" as *u8) 35 total=total+1; pass=pass+chk("P1 preamble non-empty\x00" as *u8, (pl > 200) as i64) 36 total=total+1; pass=pass+chk("P2 neutralizes programmatic click (HTMLElement.prototype.click)\x00" as *u8, g_has(pre, pl, "HTMLElement.prototype.click" as *u8)) 37 total=total+1; pass=pass+chk("P3 decoys window.open (popunder)\x00" as *u8, g_has(pre, pl, "window.open=function" as *u8)) 38 total=total+1; pass=pass+chk("P4 guards location.assign/replace to binaries\x00" as *u8, g_has(pre, pl, "L.assign=function" as *u8)) 39 total=total+1; pass=pass+chk("P5 silences beforeunload hijack\x00" as *u8, g_has(pre, pl, "beforeunload" as *u8)) 40 total=total+1; pass=pass+chk("P6 strips runtime download attrs (MutationObserver)\x00" as *u8, g_has(pre, pl, "MutationObserver" as *u8)) 41 total=total+1; pass=pass+chk("P7 knows binary payload exts (.exe/.apk)\x00" as *u8, (g_has(pre, pl, ".exe" as *u8) & g_has(pre, pl, ".apk" as *u8)) as i64) 42 total=total+1; pass=pass+chk("P8 no '!' in emitted JS (literal-mangle canary)\x00" as *u8, (g_count_byte(pre, pl, 33) == 0) as i64) 43 total=total+1; pass=pass+chk("P9 no '#' in emitted JS (literal-mangle canary)\x00" as *u8, (g_count_byte(pre, pl, 35) == 0) as i64) 44 total=total+1; pass=pass+chk("P10 neutralizes form.submit to a binary (HTMLFormElement.prototype.submit)\x00" as *u8, g_has(pre, pl, "HTMLFormElement.prototype.submit" as *u8)) 45 46 // ---- a hostile page: forced-download anchor + meta-refresh-to-payload + a display AD to preserve ---- 47 let page: *u8 = "<html><head><title>t</title><meta http-equiv=\"refresh\" content=\"0;url=https://evil.tld/p.apk\"></head><body><a id=dl href=\"https://evil.tld/malware.exe\" download>grab</a><iframe class=ad-banner src=\"https://ads.example/imp\"></iframe><div class=ad>sponsor</div></body></html>" as *u8 48 let plen2: i64 = g_slen(page) 49 let out: *u8 = sys_mmap(65536) 50 let ol: i64 = wh_neutralize(out, 65536, page, plen2, pre, pl) 51 pw("neutralized bytes: " as *u8); pn(ol); pw("\n" as *u8) 52 53 total=total+1; pass=pass+chk("N1 preamble injected into page\x00" as *u8, g_has(out, ol, "HTMLElement.prototype.click" as *u8)) 54 let ib: i64 = g_find(out, ol, "<body" as *u8, 0) 55 let ip: i64 = g_find(out, ol, "HTMLElement.prototype.click" as *u8, 0) 56 total=total+1; pass=pass+chk("N2 preamble runs before <body>\x00" as *u8, ((ip >= 0) & (ib >= 0) & (ip < ib)) as i64) 57 total=total+1; pass=pass+chk("N3 http-equiv (meta-refresh/CSP) neutralized\x00" as *u8, (g_has(out, ol, "http-equiv" as *u8) == 0) as i64) 58 total=total+1; pass=pass+chk("N4 http-equiv rewritten to inert data-equiv\x00" as *u8, g_has(out, ol, "data-equiv" as *u8)) 59 total=total+1; pass=pass+chk("N5 page content preserved (the link is still there)\x00" as *u8, g_has(out, ol, "malware.exe" as *u8)) 60 total=total+1; pass=pass+chk("N6 display ad iframe preserved (revenue-neutral)\x00" as *u8, g_has(out, ol, "class=ad-banner" as *u8)) 61 total=total+1; pass=pass+chk("N7 ad div preserved\x00" as *u8, g_has(out, ol, "sponsor" as *u8)) 62 total=total+1; pass=pass+chk("N8 title preserved (page renders)\x00" as *u8, g_has(out, ol, "<title>t</title>" as *u8)) 63 64 pw("== web-harden gate: " as *u8); pn(pass); pw("/" as *u8); pn(total); pw(" ==\n" as *u8) 65 if pass == total { sys_exit(0); return 0 } 66 sys_exit(1) 67 return 1 68}