--- type: client name: glaztech display_name: Glaz-Tech Industries last_compiled: 2026-06-04 compiled_by: DESKTOP-0O8A1RL/claude-main sources: - clients/glaztech/session-logs/2026-04-20-session.md - clients/glaztech/session-logs/2026-04-21-session.md - clients/glaztech/session-logs/2026-05-28-session.md - clients/glaztech/session-logs/2026-06-02-session.md - clients/glaztech/session-logs/2026-06-03-session.md - clients/glaztech/session-logs/2026-06-04-session.md - clients/glaztech/reports/2026-04-17-phishing-incident-report.md - clients/glaztech/reports/2026-06-03-pci-cardholder-data-finding.md - clients/glaztech/reports/2026-06-03-website-security-assessment.md - clients/glaztech/PROJECT_STATE.md - clients/glaztech/README.md backlinks: [] --- # Glaz-Tech Industries ## Profile - **Contract type:** Managed (long-term — ~15 years per session logs) - **Key contacts:** Steve Eastman — seastman@glaztech.com — internal IT, ~200 users, 9 locations. Desktop-level tech; guides technical direction, ACG implements. Tom (last name not recorded) — internal dev, author of the GTIware/GlazGTI PSA (the internal software that stores card-on-file data). - **Billing rate:** [unverified — not recorded in session logs] - **Syncro customer ID:** 143932 - **Active tickets:** #32186 (M365 Security Review / MFA, In Progress as of 2026-04-21), #32376 (Apex 404 + redirect, Resolved, 2026-06-03), #32377 (CyberSource TLS payment outage, Resolved, 2026-06-03), #32378 (Security assessment / PCI remediation, **Waiting on Customer** as of 2026-06-03 — assessment + reports delivered, Tom replied, client to remediate) - **Prepaid block remaining:** ~22.25 hrs (drew 26.5 → 22.25 on 2026-06-03) - **GuruRMM client ID:** d857708c-5713-4ee5-a314-679f86d2f9f9 - **GuruRMM site:** SLC - Salt Lake City (Site ID: 290bd2ea-4af5-49c6-8863-c6d58c5a55de) ## Infrastructure ### Servers & Services Multi-site Windows environment (~200 users, 9 locations). Active Directory confirmed (OUs referenced in deployment scripts). IP range: 192.168.0.0/24 through 192.168.9.0/24 (10 site subnets, one per site). | Server | Role | OS / Build | Local IP | Public IP | Notes | |---|---|---|---|---|---| | WWW | IIS web server — customer/e-commerce site | Windows Server 2019 Standard, build 10.0.17763.8755 (patched ~May 2026) | 192.168.8.72 | 65.113.52.88 | IIS 10.0, .NET 4.8; site `glaztech_new` at `D:\web\glaztech_4`; full VB.NET source on disk (not precompiled); LE cert CN=www.glaztech.com, SAN apex+www, exp 2026-08-19 via Certify The Web (HTTP-01); GuruRMM agent 455a1bc7-1c29-42bc-b597-fa1e64f08eec (v0.6.54); **doubles as dev workstation** (VS 2015+2022 installed — see Security Posture); active IIS site W3SVC4 (log dir `C:\inetpub\logs\LogFiles\W3SVC4`; older sites W3SVC1/2/3 stale, last writes 2018–2022) | | GTI-INV-SQL | SQL Server — website backend + GTIware PSA (shared instance) | [unverified — Server OS not confirmed; co-located with GTI/Glaztech infra] | 192.168.8.62,3436 | — | **Hostname: GTI-INV-SQL.** Login `tom` = named SQL login (SQL auth, created 2018), **member of `sysadmin` server role** (also securityadmin, dbcreator, db_owner); password embedded in site `Web.config` (NOT vaulted). **46 databases total:** all offices' `glaz_prod*` + `*_archive` databases, PDF stores, `qqest` (TimeForce payroll), `gti_samsara`, `mas_gti` (Sage 100), system DBs (`master`, `msdb`). Other sysadmin logins on instance: `GTI-INV-SQL\Administrator`, `NT SERVICE\*`, `sa` (enabled), `tom`. | | Service | Details | Notes | |---|---|---| | M365 tenant | glaztechindustries.onmicrosoft.com | ~200 users, basic licensing (no Entra P1) | | Exchange Online | glaztech.com | MailProtector inbound filter (MX 5 primary) | | Active Directory | glaztech.com domain | [unverified — AD inferred from OU references in scripts] | | Payment processing | CyberSource REST (api.cybersource.com/pts/v2/payments) — PNC merchant processor for card payments; CyberSource SOAP toolkit for eCheck/ACH (cybs.log) | Card path: online-payment-pnc.aspx; eCheck path: ach.aspx. Card-on-file auto-pay engine is GTIware (`gt_auto_process_2020.dll`) — not the website. | | GTIware PSA | Internal PSA (Tom's software): `glaztech_utilities_2020.dll` + `gt_auto_process_2020.dll` — staff-operated card-on-file system. Writes `cc_file` rows stamped with staff usernames. Shares `GTI-INV-SQL` with the public website. | Cards stored by GTIware, NOT by the website (website's `.aspx`/`.vb` has zero `cc_file`/`save_cc_data` references). | ### Email & Identity - **M365 tenant:** glaztechindustries.onmicrosoft.com - **Tenant ID:** 82931e3c-de7a-4f74-87f7-fe714be1f160 - **Primary domain:** glaztech.com - **Inbound mail filter:** MailProtector — `glaztech-com.inbound.emailservice.io` (MX 5, sole MX as of 2026-04-17) - **MailProtector IPs (EFSkipIPs on inbound connector):** 162.248.93.233, 162.248.93.81, 65.113.52.82 - **DMARC:** p=reject; sp=reject (hardened 2026-04-17, was p=none) - **DKIM:** CNAME records exist for selector1/selector2 — active status unverified [WARNING: confirm DKIM is active in M365] - **MFA status:** [WARNING] DISABLED as of 2026-04-21. Security Defaults off. No Conditional Access (requires Entra P1, not licensed). ~160 users with password-only sign-in. MFA rollout is open work item — do not enable Security Defaults until service account audit is complete (see Active Work). - **Licensing:** Basic M365 (no Entra P1 / Business Premium). Per-user MFA or Security Defaults are the available free options. - **Mailbox forwarding (internal, low risk):** Payroll@glaztech.com → carmen@glaztech.com; TUCCSR@glaztech.com → bryce@glaztech.com - **OAuth consent grants:** 38 grants — not audited as of last session - **EXO PowerShell:** ExchangeOnlineManagement 3.9.2. `Get-MessageTrace` deprecated Sept 2025 — use `Get-MessageTraceV2` (no `-PageSize` parameter). ### Exchange Online Transport Rules Full transport rule list as of 2026-06-02: | Priority | Name | Condition | Action | State | |---|---|---|---|---| | 0 | Pensky Allow | [unknown] | [unknown] | Enabled | | 1 | GTIMail No-Reply - Reject Inbound | SentTo: gtimail@glaztech.com | RejectMessageAction | Enabled | | 2 | SCL Bypass - hartsglass + olemons (SHVSALES) | From: hartsglass@centurytel.net, olemons@eastexglass.com, SSales@arkglass.com, bossier@glassservices.com | SetSCL -1 | Enabled | | 3 | SCL Bypass - aaaglassinc.com (SHVSALES) | SenderDomainIs: aaaglassinc.com | SetSCL -1 | Enabled | | 4 | SCL Bypass - noreply@azcomputerguru.com (MailProtector digests) | From: noreply@azcomputerguru.com | SetSCL -1 | Enabled | Rule GUIDs: Priority 2 = 482c714a-8780-4c62-ae0a-0b6da9ca9d52; Priority 3 = 7e0c01a8-ec22-43fe-b600-796c0f295aa5. GUIDs for Priority 0, 1, 4 not recorded. Note on Priority 1: The "GTIMail No-Reply - Reject Inbound" transport rule rejects ALL inbound mail to gtimail@glaztech.com, which causes the daily MailProtector digest for that address to fail. This is a pre-existing rule — review with Steve is pending (see Active Work). ### Inbound Connector - **Name:** "Inbound Spam Filter" - **Type:** Partner - **RequireTls:** True - **EFSkipIPs:** 162.248.93.233, 162.248.93.81, 65.113.52.82 (MailProtector IPs) - **SCLMinusOne:** null (EOP re-evaluates all mail; do NOT change to true — too broad) - **SenderIPAddresses restriction:** None (intentional — avoids blocking calendar invites from external M365 tenants) ### Network - **Sites:** 9 locations - **IP ranges:** 192.168.0.x through 192.168.9.x (one subnet per site — up to 10 sites) - **Firewall/ISP:** [unverified — not documented] - **DNS hosted on:** IX server (172.16.3.10), PowerDNS. Zone file: `/var/named/glaztech.com.db` ## Access - **Remediation tool:** ComputerGuru apps consented in tenant (Exchange Operator, Security Investigator, Tenant Admin, Defender Add-on) - **Exchange Operator App ID:** b43e7342-5b4b-492f-890f-bb5a4f7f40e9 - **Exchange Operator cert thumbprint:** A615823DE1CAF15229027DEC075AFE32B900D82C (not in Windows cert store on BEAST — use `get-token.sh` bearer token flow) - **Remediation tool app (AI):** fabb3421-8b34-484b-bc17-e46de9703418 - **Exchange Admin role:** Assigned to ACG service principal in Entra - **Global Admin account:** admin@glaztechindustries.onmicrosoft.com (ACG admin only — external GA from tomakkglass.com removed 2026-04-21) - **Vault path:** `clients/glaztech/` [no SOPS credential file documented — remediation tool uses MSP-wide app credentials] - **Exchange Operator vault:** `msp-tools/computerguru-exchange-operator.sops.yaml` - **Token acquisition:** `bash .claude/skills/remediation-tool/scripts/get-token.sh exchange-op` → `Connect-ExchangeOnline -AccessToken $token -Organization 'glaztechindustries.onmicrosoft.com'` - **DNS access:** `root@172.16.3.10` (IX server) - **Deploy (endpoints):** GuruRMM (preferred) or ScreenConnect - **MailProtector / CloudFilter partner portal:** NO credentials in vault — manual partner-portal login required for any MailProtector changes (provisioning, spam summary enable). Consider vaulting. - **Glaztech SQL login (`tom`):** present in `D:\web\glaztech_4\Web.config` connectionStrings — NOT in vault. Used read-only for the 2026-06-03 assessment only; do NOT use outside of authorized sessions. This login has sysadmin rights on `GTI-INV-SQL` — treat with corresponding care. ## Security Posture — CRITICAL (Active Issue — Ticket #32378) **Classification: CONFIDENTIAL/Security.** Full detail in: - `clients/glaztech/reports/2026-06-03-pci-cardholder-data-finding.md` - `clients/glaztech/reports/2026-06-03-website-security-assessment.md` (incl. Appendix A — Intrusion/Brute-Force Log Review, 2026-06-04) A full read-only security assessment of the Glaztech e-commerce web application and SQL backend was performed 2026-06-03. A follow-up read-only intrusion/brute-force log review was performed 2026-06-04 (see Appendix A in the assessment report). Overall risk: **CRITICAL**. Key findings (no card numbers or passwords are reproduced here): ### C0 (TOP CRITICAL) — Website connects to `GTI-INV-SQL` as `sysadmin` **This is the single most dangerous finding.** The public website at `D:\web\glaztech_4` logs into the SQL server `GTI-INV-SQL` (192.168.8.62,3436) using SQL login **`tom`** — a **named SQL login** (SQL authentication, created 2018, NOT the built-in `sa`) that is a **member of the `sysadmin` server role** (also securityadmin, dbcreator, db_owner). The password is **embedded in the site's `Web.config`** on the internet-facing server. That same SQL instance (`GTI-INV-SQL`) is **shared with GTIware** (Tom's internal PSA) and hosts **46 databases**: all offices' `glaz_prod*` + `*_archive`, PDF stores, `qqest` (TimeForce payroll), `gti_samsara`, `mas_gti` (Sage 100), and system DBs. Because a SQL injection executes as the connecting login, the website's `quo()` SQLi flaw executes with **full sysadmin rights across the entire instance**. Cross-database reach was confirmed live: from a single injectable page on the Tucson connection, other offices' `cc_file` tables were read (`glaz_prod_phx` = 141 rows, `glaz_prod_den` = 190, `glaz_prod_elp` = 179). **Attack chain:** (1) guess one website customer login (no lockout, username = account number, passwords as short as 3 chars, plaintext) → (2) hit an injectable payment page → (3) inject as sysadmin → total control of `GTI-INV-SQL`. As sysadmin an attacker can: steal every stored card PAN+CVV and password; DROP/encrypt all 46 databases (every office, all archives); commit fraud; enable `xp_cmdshell` → OS-level code execution on the SQL server → network pivot into the GTI/Glaztech environment. **One guessed website login + the SQLi = full theft, destruction, or ransom of the entire GTIware database server.** **Required remediation — do this FIRST:** 1. Pull the `tom` sysadmin login from the website. Give the site a **dedicated least-privilege login** scoped only to the tables/views/procs it needs, with **no access to GTIware databases** (no `cc_file`, no other offices, no archives). 2. **Separate the website's data from GTIware.** The internet-facing app must not share a SQL instance with the internal PSA's cardholder data. 3. **Stop storing cards on-prem** — call the processor's API/hosted vault directly (no card data lands on Glaztech systems), or at minimum tokenize (store a token, never the PAN). CVV must never be stored — PCI Req 3.2, no exception. 4. Fix the SQLi (parameterize all queries, remove `quo()`); add login lockout/rate-limiting. ### Cardholder Data — PCI-DSS Violations (Req 3.2 + 3.4) **Storage attribution (IMPORTANT):** The website stores **NO** cards. The website's `.aspx`/`.vb` files have zero `cc_file`/`save_cc_data`/`gt_auto_process` references; the quick-pay pages even carry a disclaimer that no card info is saved. The plaintext cards are written by **GTIware** — Tom's internal PSA (`glaztech_utilities_2020.dll` + `gt_auto_process_2020.dll`, compiled libs in the site `Bin` but not called by the site). Recent `cc_file` rows are stamped with staff usernames (Victoria, Bryce, Diana) and notes like "RUN CARD WHEN REQUESTED" — a back-office card-on-file workflow. The website is the **access vector** (C0), not the storer. - **`cc_file` (~780 saved cards):** Full PAN stored in plaintext in every per-office database (`glaz_prod`, `glaz_prod_phx`, `glaz_prod_slc`, `glaz_prod_elp`, `glaz_prod_den`, `glaz_prod_alb`, `glaz_prod_boi`, `glaz_prod_brl`, `glaz_prod_shp`, `glaz_prod_corp`). Zero encrypted rows. `cc_file.cc_code` retains CVV/CID (50/54 rows in tuc; mirrors expected in all offices). **CVV retention is a PCI Req 3.2 violation — indefensible; no exception even if encrypted.** - **`cof_payments_header` (historical payments):** Phoenix alone: 14,496 rows, 11,794 plaintext PANs. Tuc: 2,245 rows, ~367 plaintext + ~597 formatted. Years of transaction history with recoverable card numbers. - **Why cards are stored:** Card-on-file invoice auto-pay. `i_get_cc_on_file_invoices` joins `invoice` × `cc_file`; `gt_auto_process_2020.dll` reads stored PANs and bills them via CyberSource. `get_cc_data` is `SELECT * FROM cc_file` (returns full PAN+CVV; IDOR-shaped on `@acctno`). Stale copies in `Old_bin`/`Old_code\Bin`. **Feature can be preserved by migrating to the chosen processor's token vault — store a token reference instead of the raw PAN.** - **Containment:** Exposure is contained to the GTIware card-on-file tables (`cc_file`, `cof_payments_header`) in the 15 custom web-app databases on `GTI-INV-SQL` (192.168.8.62). The Sage 100 ERP DB (`mas_gti`) stores **no** cardholder data — its native CC module is **disabled** (`SY_Company.CreditCardEnable=N`, `AR_CustomerCreditCard`=0 rows; tokenization columns exist in the schema but are unused). Sage is **not** a cardholder-data location. **Database backups also contain plaintext PANs — cleanup must address backups, not just live data.** - **Processor reality (verified 2026-06-03):** despite a belief that processing moved to "Payrilla/Paya," the website is **still on CyberSource/PNC** (no Payrilla anywhere in site code/config) and **still writing plaintext cards daily** (`cc_file` last write tuc 2026-06-03 14:15, phx 10:19; live `CC-WebPayment-PNC` txns today). Sage's CC module is off. Payrilla, if used, is a **separate channel not visible in either system and not connected to the website** — the website exposure is unchanged. Anomaly: `cc_file` absent in the `corp` DB though present earlier 2026-06-03 — needs a look. ### Authentication — Plaintext Passwords - `web_security` table: ~9,000+ plaintext customer passwords (corp 6,017 + tuc 3,012 confirmed, other offices expected); 0 hash-like values; lengths 3–19 chars; no complexity enforcement. - Auth stored proc `get_web_accesslevel`: `WHERE acct_no=@username AND web_password=@passwd` — direct plaintext comparison. - Employee "forgot password" flow emails the user their existing plaintext password — possible only with reversible/plaintext storage. - No account lockout, no rate-limiting; username = customer account number (guessable). ### SQL Injection — `quo()` Helper ```vb Function quo(stext) As String Return "'" + stext + "'" ' wraps in quotes, does NOT escape embedded quotes End Function ``` Used to build concatenated dynamic SQL in payment pages (`ach.aspx.vb`, `quick-pay-ach.aspx.vb`, `quick-pay-pnc.aspx.vb`, `quick-pay.aspx.vb`, `order-detail*`). 59 concatenated SQL statements identified (~10 joining user input). The login path itself is parameterized (sproc) and not injectable; 948 parameterized calls elsewhere. **Any input containing `'` breaks out and allows injection; because the site connects as sysadmin, injection = full instance compromise (see C0).** ### Other Critical/High Findings | Finding | Severity | |---|---| | Reflected XSS: `gt_errorpage.aspx` — `errmsg` query param → `lblerr.Text` unencoded | High | | `debug="true"` + `customErrors=Off` + exceptions echoed to users in URLs | High | | Production server is also a dev workstation: VS Community 2015 + 2022, .NET 8 SDKs, MSBuild, IIS Express, full VB.NET source on disk | High | | Remote-access sprawl: RealVNC Enterprise E4.2.8 (~2009, EoL), stale ScreenConnect v6.0.11622 (2018), Splashtop, Datto RMM+EDR, Syncro, GuruRMM (6+ agents) | High | | Server listener accepts TLS 1.0 + 1.1 (SChannel Enabled=1) | High | | Single shared SQL login (`tom`) with sysadmin rights; creds in `Web.config` in cleartext | High | | No Secure/HttpOnly cookies; no session regeneration on login; session-fixation risk; no MFA, no lockout; H5 detection blind spot (see below) | High | ### H5 Detection Blind Spot — No Failed-Login Visibility The employee login (`/emp/employee-login.aspx`) returns **HTTP 200 on both success and failure** — the status code is NOT a success/failure signal for staff logins (no post-redirect-get pattern). The app logs **no failed login attempts** anywhere, and app-level auth never touches the Windows Security log. The net effect: a slow credential-guessing attack against staff or customer accounts would be **effectively invisible** — there is no lockout to stop it and no log to detect it after the fact. (Confirmed during the 2026-06-04 log review — see Appendix A of the assessment report.) **Fix:** add failed-login logging (timestamp, username, source IP) to the application; add account lockout/throttling; consider MFA for employee/admin access. ### Attack Chain Summary Obtain a customer login (LOW difficulty — no lockout, guessable username = account number, plaintext passwords as short as 3 chars) → access payment pages → SQL inject with `quo()` → executes as **sysadmin** on `GTI-INV-SQL` → full read/write/DROP of all 46 databases, `xp_cmdshell` OS takeover, network pivot. **Every compensating control (lockout, password hashing, PAN encryption, parameterized queries, least-privilege DB login) is absent; first failure is last failure.** ### Intrusion / Brute-Force Log Review — 2026-06-04 (No Evidence of Attack) A read-only review via GuruRMM was performed 2026-06-04 covering 7 days of IIS logs (`W3SVC4`, ~52,000 requests, May 29 – Jun 4) and the Windows Security event log (4625/4624, 7-day window; log retains back to 2026-03-31). **Bottom line: NO evidence of a brute-force attack — not against the website logins, and not against the Windows server.** - **Website logins (IIS):** Customer login (`/customer_login.aspx`) shows 2,547 HTTP 302 (success) / 78 HTTP 200 / 5 HTTP 500 across 740 distinct IPs — normal traffic. Employee login (`/emp/employee-login.aspx`) showed 77 HTTP 302 / 381 HTTP 200 / 6 HTTP 500; the apparent imbalance is an artifact — the employee login returns HTTP 200 on BOTH success and failure (no redirect-on-success). Top "suspect" IP `160.3.157.9` (24 hits) is a single legitimate employee on an iPhone checking timecards. No brute-force / credential-stuffing signature (no rapid high-volume POSTs, no username-cycling at machine speed, no bot UAs). - **HTTP 500 bursts (open item):** Scattered bursts of HTTP 500 on post-login pages (`invoices.aspx`, `quotes.aspx`, `place_orders.aspx`, `billing-statements.aspx`, `online-payment-pnc.aspx`) from IPs `201.146.179.166`, `64.178.182.162`, `205.185.107.49`, `172.87.137.60` — 8–17 identical 500s within a single second per IP. Not classified as a brute-force campaign, but given C3 (the `quo()` SQLi path), a quote character in input on those pages produces exactly a 500 error — worth an app-side look. IIS does not log POST bodies, so attempted inputs are not recoverable. - **Windows Security log:** Only 13 failed logons (4625) in 7 days — all LogonType 3 (SMB/network), 100% from internal LAN IPs, zero from any public IP. No RDP (type 10) failures at all. Targeted usernames: 12 blank (null/anonymous SMB) + 1 `tomabens` (internal stale credential). No successful remote logons from any external IP. Inference: RDP/SMB are not internet-exposed — no external host got in at the OS auth layer. - **Detection gap confirmed (see H5):** The review found no attacker, but confirmed that a slow guessing attack would currently be undetectable without failed-login logging + lockout. Both are already on the #32378 remediation roadmap. Full detail in `clients/glaztech/reports/2026-06-03-website-security-assessment.md` (Appendix A). ### Remediation Roadmap (Ticket #32378 — Waiting on Customer) **Now (days) — requires client sign-off:** 1. Pull sysadmin login from the website: give the site a dedicated least-privilege login with no access to GTIware/card data (this alone cuts the blast radius of a breach from "total GTIware compromise" to "website DB only") 2. Purge stored CVV (`cc_file.cc_code`, backup-first — needs Tom/Steve explicit sign-off) 3. `debug="false"` + `customErrors="On"`; HTML-encode `gt_errorpage.aspx`; stop echoing exception text to users 4. Remove RealVNC 4.2.8 and stale ScreenConnect v6 5. Disable TLS 1.0/1.1 on the IIS/SChannel listener **Short term (weeks):** 6. Hash all passwords (PBKDF2/bcrypt/Argon2); replace email-the-password flow with reset-token flow; force global reset 7. Parameterize all concatenated SQL in payment pages; delete `quo()` 8. Add Secure+HttpOnly cookies, session regeneration on login, login throttling/lockout, **failed-login logging (timestamp, username, source IP)** 9. Migrate card-on-file to the chosen processor's token vault (CyberSource or new provider — confirm which flows actually route through "Payrilla"); purge/encrypt historical `cc_number` columns; address backups **Structural:** 10. Separate dev from production; deploy precompiled; remove SDKs/IDE/source from prod host 11. Least-privilege SQL accounts per function; secret management for Web.config connection strings; TDE at rest; re-scope merchant PCI SAQ after remediation ## Patterns & Known Issues - **Phishing via direct-to-M365 MX bypass:** Two phishing campaigns in April 2026 succeeded because DNS had a secondary MX record (`glaztech-com.mail.protection.outlook.com` at priority 10) that bypassed MailProtector. Hardened: MX 10 removed, DMARC to p=reject, Enhanced Filtering for Connectors enabled. Do not re-add a secondary MX record. - **Inbound connector IP restriction:** Do NOT restrict `SenderIPAddresses` on the "Inbound Spam Filter" connector — blocks legitimate calendar invites from external M365 tenants (learned from Dataforth incident). EFSkipIPs are set to MailProtector IPs instead. - **Do NOT set SCLMinusOne=true on connector:** This would trust MailProtector's verdict for all inbound mail — too broad. Use targeted transport rules for specific senders instead. - **DMARC-rejecting vendor senders:** With Enhanced Filtering enabled, EOP looks past MailProtector to the original sender's SPF/DKIM/DMARC. Vendors with `p=reject` domains (e.g., centurytel.net, eastexglass.com) get hard 550 5.7.509 NDR rejections. Fix: SCL=-1 transport rule scoped to the specific sender address or domain. Transport rules evaluate before DMARC enforcement in EOP. - **EXO transport rule name limit:** 64-character maximum. Plan names accordingly. - **EXO REST API:** Direct `/TransportRule` REST endpoints 404 in this tenant. Use `InvokeCommand` pattern: `POST /adminapi/beta/{tenant}/InvokeCommand` with `{"CmdletInput": {"CmdletName": "New-TransportRule", "Parameters": {...}}}`. - **Service accounts need audit before MFA rollout:** Shoretel, mitel, Gti-FaxFinder, GTIMail, GTIQUOTE, CAS1944, clerk — all need SMTP/auth method confirmation before Security Defaults can be enabled. - **PDF preview broken (MOTW):** Windows KB5066791/KB5066835 broke PDF preview on network shares via Mark of the Web. Fix scripts are ready in `clients/glaztech/` — deployment is pending (as of 2026-03-30). - **clearcutglass.com DMARC history:** Corena Spottsville (clearcutglass.com) emails to seastman and zulema were rejected. Temporary transport rule (SCL=-1) was set and removed on 2026-04-21. SPF ~all weakness noted to Team Logic IT (Jordan Fox, jfox@tlit60302.com); recommend they harden to -all and confirm DKIM. - **glassservices.com SPF broken:** `bossier@glassservices.com` publishes `v=spf1 -all` — rejected by all mail providers. SCL=-1 rule covers this as a workaround. Steve should notify vendor to fix SPF. - **Client tone:** ACG has managed GlazTech ~15 years. Steve Eastman is a trusted internal IT partner. Comments and communication should lead with what we know, state findings and actions taken, ask only one targeted question if needed — not open-ended discovery. - **Unlicensed accounts (pending Steve confirmation):** Chauntelle@glaztech.com, Denouser1@glaztech.com, Gti-FaxFinder@glaztech.com. - **IIS apex binding — always add both http:80 and https:443 for the bare domain:** The glaztech_new IIS site originally had only a www host-header binding. Apex (glaztech.com) returned 404 from HTTP.sys (not a 301 redirect, a real 404) because no binding matched. Fix: add `http/IP:80:glaztech.com` + `https/IP:443:glaztech.com` bindings reusing the existing SAN cert. When adding HTTP→HTTPS redirect via URL Rewrite, always include a negate condition on `/.well-known/acme-challenge/` so Certify The Web (HTTP-01) LE renewals are not blocked. - **Legacy .NET + modern payment gateway TLS:** .NET Framework 4.x apps on Windows Server 2019 do NOT automatically use TLS 1.2 unless the registry keys `SchUseStrongCrypto=1` + `SystemDefaultTlsVersions=1` are set under BOTH `HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319` AND `HKLM\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319`. Payment gateways (CyberSource, etc.) that drop TLS 1.0/1.1 will silently fail with "Could not create SSL/TLS secure channel" without this fix. App pool recycle required after registry change. Verify via the payments DB (look for fresh approvals), not just a TLS probe. - **MailProtector digest provisioning is per-mailbox on the MailProtector side:** The SCL=-1 transport rule (Priority 4) ensures digest emails from `noreply@azcomputerguru.com` are not spam-filtered by EOP — but a mailbox that was never provisioned in MailProtector will never receive a digest regardless of EOP rules. Confirmed via message trace (shannon@glaztech.com: 629 digests sent to ~60 recipients over 10 days, 0 to Shannon). Fix is on the MailProtector partner portal — no Exchange change needed. - **Glaztech custom web app — stored card feature requires tokenization to remediate safely:** Cards in `cc_file` are there for GTIware auto-pay via `gt_auto_process_2020.dll`. Deleting the PANs without a replacement breaks the auto-billing feature. The safe path is processor token vault migration (tokenize on write, replace stored PAN with token, update `gt_auto_process` to bill by token). Quick win: purge CVV (`cc_code`) immediately — this has no functional impact and is the fastest PCI Req 3.2 remediation. - **Glaztech SQL login (`tom`) + Web.config creds are NOT in the SOPS vault.** Do not commit these credentials. If future automation needs SQL access, vault them first. This login has sysadmin rights — treat any use with corresponding care. - **Internet-facing website + internal PSA (GTIware) share one SQL instance; website connects as sysadmin → any website SQLi = full internal-DB compromise.** The public website (`WWW`, 65.113.52.88) and GTIware (the internal card-on-file PSA) both use `GTI-INV-SQL` (192.168.8.62,3436). The web login `tom` is sysadmin. A SQL injection on the website executes as sysadmin against the entire 46-DB instance — cross-DB reads confirmed live. Public web apps must use least-privilege DB logins isolated from internal data. Internet-facing apps must never share a SQL instance with an internal PSA without strict permission partitioning. - **Employee login HTTP 200 on both success and failure — status code is not a success/failure signal; no failed-login logging exists:** `/emp/employee-login.aspx` returns HTTP 200 regardless of outcome (no redirect-on-success pattern). The application logs no failed login attempts anywhere, and app-level auth does not generate Windows Security log events. A slow credential-guessing campaign against staff or customer accounts would be completely invisible: no lockout triggers, no log to audit after the fact. Confirmed during the 2026-06-04 log review — the 381 "200 responses" on the employee portal that initially appeared anomalous proved to be normal authenticated sessions. Fix: add failed-login logging + account lockout. Do not treat HTTP status code as an auth-outcome signal on this endpoint. ## Active Work ### PDF Preview Fix (DEPLOYMENT-READY — pending execution) Scripts in `clients/glaztech/`: - `Fix-PDFPreview-Glaztech-UPDATED.ps1` — updated remediation (recommended) - `Fix-PDFPreview-Glaztech.ps1` — original - `Deploy-PDFFix-BulkRemote.ps1` — bulk remote deployment - `GPO-Configuration-Guide.md` — GPO method - `QUICK-REFERENCE.md` — summary of all three methods Deploy via Option A (ScreenConnect, individual), Option B (bulk remote via PS remoting), or Option C (GPO). Waiting on file server hostnames/IPs from Steve before bulk deploy. ### MFA Rollout (Ticket #32186 — In Progress) Waiting on Steve's reply to: 1. Service account auth methods (which use SMTP basic auth or password-only flows?) 2. Disposition of unlicensed accounts (Chauntelle, Denouser1, Gti-FaxFinder) 3. Licensing preference: Security Defaults (free, no exclusions) vs. per-user MFA (free, can exclude service accounts) vs. Conditional Access (requires Entra P1/Business Premium, ~$22/user/mo) **Do not enable Security Defaults until service accounts are confirmed safe.** MFA rollout plan: Phase 1 — user communication (install Authenticator); Phase 2 — enable enforcement; Phase 3 — follow-up stragglers; Phase 4 (future/P1) — Conditional Access with trusted IPs for office locations. ### Website Security Remediation (Ticket #32378 — Waiting on Customer) Security assessment complete 2026-06-03. Intrusion/brute-force log review complete 2026-06-04 (no attacker found; detection gap confirmed). Assessment and reports delivered to client (Steve/Tom). Tom replied 2026-06-03 confirming that the website stores no cards (correct); investigation of his reply surfaced C0 (sysadmin login). Reply posted on #32378 explaining the sysadmin+SQLi chain and the four required remediations. Ticket set to **Waiting on Customer** — Tom/Steve to remediate. ACG can execute quick wins (CVV purge, least-privilege login, debug-off) on client go-ahead. Key actions queued but not yet executed (require client sign-off): - Pull `tom` sysadmin login from the website → replace with least-privilege login that cannot see GTIware data (HIGHEST PRIORITY) - Purge CVV from `cc_file.cc_code` (backup-first; needs explicit go-ahead from Tom) - `debug="false"` + `customErrors="On"` — can apply quickly with low risk - Remove RealVNC 4.2.8 and stale ScreenConnect v6 - Disable TLS 1.0/1.1 on IIS/SChannel listener - Add failed-login logging + account lockout (reinforced by 2026-06-04 log review finding) - App-side investigation of HTTP 500 bursts on post-login pages (possible SQLi error path) — IPs `201.146.179.166`, `64.178.182.162`, `205.185.107.49`, `172.87.137.60`; not yet handed to Tom ### gtimail@glaztech.com Daily Digest Failure (Pending — review with Steve) The "GTIMail No-Reply - Reject Inbound" transport rule (Priority 1) rejects all inbound mail to `gtimail@glaztech.com`, causing the daily MailProtector digest for that address to fail every day. This is a pre-existing rule and was not modified. Confirm with Steve Eastman whether `gtimail@glaztech.com` should receive MailProtector digests — if so, the rule needs an exception or the recipient needs to be removed from the MailProtector digest list. ### shannon@glaztech.com — MailProtector Digest Not Received (Pending — MailProtector portal) Message trace confirmed shannon@glaztech.com receives no MailProtector digests at all (0 of 629 digests over 10 days). This is a MailProtector-side provisioning issue — she is not provisioned/enabled in the MailProtector spam summary settings. No Exchange change needed. Fix: log into the MailProtector partner portal and enable the Spam Summary for shannon@glaztech.com. No vault credentials exist for MailProtector — manual portal access only. ### Pending follow-ups - Audit 38 OAuth consent grants (not done as of 2026-04-21) - Confirm DKIM signing active in M365 for glaztech.com - Monitor DMARC aggregate reports (rua=noreply@glaztech.com — should be a monitored mailbox or reporting service) - Security awareness training for staff (multiple employees forwarded and replied to obvious phishing in April 2026) - Review whether any user clicked phishing links (check sign-in logs for suspicious auth attempts post-April 17) - Notify Steve: glassservices.com vendor needs to fix their SPF record (`v=spf1 -all`) - Harts Glass original rejected emails need to be resent by sender — our SCL bypass is live but NDR'd messages do not auto-retry - Consider creating retroactive Syncro ticket for 2026-05-28 SHVSALES email delivery work - Monitor continued card payment success on WWW after 2026-06-03 TLS fix (verify `web_payment_header` for ongoing approvals) - Tom code fallback (`ServicePointManager.SecurityProtocol = Tls12` in app code) staged but not deployed — can apply if registry fix ever regresses - Investigate `corp` DB `cc_file` "Invalid object name" anomaly (existed 2026-06-03 morning with 3 rows, then returned "Invalid object name" later same day — per-office DBs unaffected) - Confirm with Tom/Payrilla which flows actually route through Payrilla, and whether a migration to tokenized card storage via the new provider is planned for the website - Optional: enumerate listening/forwarded ports on `WWW` to confirm RDP is not internet-exposed (log review strongly implies it is not; a port enumeration would make it definitive) ## History Highlights - **[~15 years prior]** Long-standing managed client. - **2026-01-27** — PDF preview break caused by Windows MOTW update (KB5066791/KB5066835). Fix scripts created. Deployment pending. - **2026-04-17** — Two phishing campaigns bypassed MailProtector via direct-to-M365 MX bypass. 32 messages purged across 8 users. Hardened: MX 10 removed, DMARC p=reject, Enhanced Filtering Connectors enabled. Remediation tool onboarded (admin consent, Exchange Admin role). Forensic evidence preserved in `clients/glaztech/reports/`. - **2026-04-20** — Exchange transport rule created to allow clearcutglass.com mail (DMARC bypass, SCL=-1) while Team Logic IT fixed their DNS. Ticket #32176 created. - **2026-04-21** — clearcutglass.com DNS fixed by Team Logic IT (Jordan Fox). Transport rule removed. External Global Admin (glaztechadmin from tomakkglass.com / Team Logic IT) removed from tenant. M365 security review surfaced: no MFA, 38 OAuth grants, unlicensed accounts, service account audit needed. Ticket #32186 opened for MFA implementation. Feedback: use expert-partner tone with Steve, not open-ended discovery questions. - **2026-05-28** — SHVSALES@glaztech.com vendor email delivery failure. Root cause: vendors (centurytel.net, eastexglass.com) publish DMARC p=reject; Enhanced Filtering re-evaluates past MailProtector relay, producing 550 5.7.509 NDR. Fix: two SCL=-1 transport rules created (Priority 2: specific addresses for hartsglass, olemons, SSales, bossier; Priority 3: aaaglassinc.com domain). glassservices.com SPF broken (`-all`) — workaround only, vendor must fix. - **2026-06-02** — MailProtector quarantine digest messages from `noreply@azcomputerguru.com` confirmed hitting `FilteredAsSpam` for some recipients (e.g., tshaw@glaztech.com). Transport rule created: "SCL Bypass - noreply@azcomputerguru.com (MailProtector digests)" at Priority 4 (From=noreply@azcomputerguru.com, SetSCL=-1). Message trace via `Get-MessageTraceV2` also revealed `gtimail@glaztech.com` failing daily due to pre-existing Priority-1 reject rule — flagged for Steve review. - **2026-06-03 (earlier)** — Three tickets on web server `WWW` (192.168.8.72 / 65.113.52.88), all via GuruRMM. (1) **Apex 404 emergency:** glaztech.com returned 404 (IIS site `glaztech_new` had www-only binding); added apex http:80+https:443 bindings (cert SAN already covered apex), then added HTTP→HTTPS 301 URL Rewrite redirect with `/.well-known/acme-challenge/` exclusion (Certify/LE HTTP-01 renewal safe). `web.config.bak-20260603-090701` created. Ticket #32376 — Resolved, 1h remote. (2) **CyberSource payment outage ("Could not create SSL/TLS secure channel"):** CyberSource (PNC merchant processor) disabled TLS 1.0/1.1; .NET 4.x on Server 2019 defaulted to old TLS. Fix: `SchUseStrongCrypto=1` + `SystemDefaultTlsVersions=1` in both `.NETFramework\v4.0.30319` hives + app pool `glaztech_new` recycle. Verified via payments DB (credit-card approval at 09:36 post-fix). Ticket #32377 — Resolved, 1.5h emergency remote. (3) **Security assessment:** read-only deep inspection of IIS config, VB.NET source, and SQL backend revealed CRITICAL posture. Sage 100 (`mas_gti`) confirmed NOT a cardholder-data location — CC module disabled (0 stored cards). Two reports created. Ticket #32378 opened. Billed 1h remote. Prepaid block: 26.5 → 22.25 hrs. Also: shannon@glaztech.com digest-not-received confirmed as MailProtector provisioning issue (not Exchange) — requires MailProtector partner-portal fix. Payrilla/CyberSource reconciliation: live system confirmed website is still on CyberSource/PNC with daily ongoing card writes. - **2026-06-03 (late — ~19:32 PT)** — **Tom (GTIware dev) replied to #32378** clarifying that the website's online payment system stores no card data — he is correct. Investigation of Tom's reply surfaced the **top critical finding (C0):** the website connects to the shared SQL server `GTI-INV-SQL` (192.168.8.62,3436) as SQL login `tom`, a **named SQL login that is a member of the `sysadmin` role** (created 2018; password in `Web.config`). The instance hosts 46 databases shared between GTIware and the website. Because SQLi executes as the connecting login, the website's `quo()` injection = sysadmin over the entire `GTI-INV-SQL` instance; cross-database card-table reads confirmed live. **Attribution corrected in both reports:** the website is the access path (C0); GTIware (staff-operated) writes the cards. Sage CC module confirmed disabled (0 stored cards, not a CHD location). Both reports updated. Plain-English reply posted to Tom on #32378 (public+emailed, comment 417070212) explaining the sysadmin+SQLi chain and the four required fixes. Ticket set to **Waiting on Customer**. - **2026-06-04** — **Read-only intrusion/brute-force log review** on `WWW` (GuruRMM agent 455a1bc7, v0.6.54). Reviewed 7 days of IIS W3SVC4 logs (~52,000 requests, May 29 – Jun 4) and Windows Security event log (4625/4624 events, 7-day window, log retained back to 2026-03-31). **Finding: NO evidence of a brute-force or intrusion attempt** against the website logins or the Windows server. Customer login traffic is normal (2,547 successes/740 IPs). Employee login: initial "381 failures" corrected — the employee login returns HTTP 200 on BOTH success and failure (status code is not an auth-outcome signal); all flagged IPs proved to be legitimate employees reaching protected pages post-login. Windows Security log: 13 failed logons in 7 days, all SMB type 3 from internal LAN IPs, zero external, no RDP failures — RDP/SMB not internet-exposed. **Key confirmation:** the H5 detection blind spot is real — 200-on-both + no failed-login logging + no lockout = a slow guessing attack would currently be completely invisible. HTTP 500 bursts on post-login pages flagged as an open app-side item. Findings folded into the security report as Appendix A. Ticket #32378 remains Waiting on Customer. ## Backlinks - `wiki/systems/ix-webhosting.md` [if exists] — DNS hosted on IX server