diff --git a/clients/glaztech/reports/2026-06-03-pci-cardholder-data-finding.md b/clients/glaztech/reports/2026-06-03-pci-cardholder-data-finding.md index 48c618f..f883984 100644 --- a/clients/glaztech/reports/2026-06-03-pci-cardholder-data-finding.md +++ b/clients/glaztech/reports/2026-06-03-pci-cardholder-data-finding.md @@ -10,9 +10,9 @@ ## Executive Summary -The custom Glaztech web application stores **full credit card numbers (PAN) in plaintext** and **retains card security codes (CVV/CID)** in its SQL databases. This is a serious PCI-DSS compliance failure and a significant breach-liability exposure. Approximately **780 saved customer cards** (card-on-file) and **tens of thousands of historical payment records** are affected, with confirmed plaintext PANs and ~hundreds of stored CVV values. +Glaztech's **internal PSA (GTIware)** stores **full credit card numbers (PAN) in plaintext** and **retains card security codes (CVV/CID)** in its SQL databases — and those databases sit on the **same SQL instance the public website connects to** (the website itself stores nothing; it is the *access path*, see the website security assessment). This is a serious PCI-DSS compliance failure and a significant breach-liability exposure. Approximately **780 saved customer cards** (card-on-file) and **tens of thousands of historical payment records** are affected, with confirmed plaintext PANs and ~hundreds of stored CVV values. -The Sage 100/MAS ERP database (`mas_gti`) is **not** the problem — it uses proper tokenization (`CreditCardGUID`, `Last4Unencrypted`, `EncryptedCreditCardNo`). **The exposure is entirely in the custom web application's own tables.** +The Sage 100/MAS ERP database (`mas_gti`) is **not** the problem — its native card module is **disabled** (`CreditCardEnable = N`, 0 stored cards). **The exposure is entirely in GTIware's card-on-file tables (`cc_file` / `cof_payments_header`), which live in the same SQL instance the public website connects to.** --- @@ -50,7 +50,7 @@ The Sage 100/MAS ERP database (`mas_gti`) is **not** the problem — it uses pro ### Finding 4 — Access controls / context - The web application connects with a **single shared SQL login (`tom`)** that has **full read on the card columns** (verified: `HAS_PERMS_BY_NAME` = 1 on `cc_number` and `cc_code`). No column-level protection or data masking. - Connection strings (with this login + password) are stored in the site `Web.config` on the web server. -- The Sage 100 DB (`mas_gti`) uses tokenization and is materially compliant by comparison — scope of this finding is the **custom web app** only. +- The Sage 100 DB (`mas_gti`) has its native card module **disabled** (0 stored cards) — scope of this finding is **GTIware's card-on-file tables**, which share a SQL instance with (and are reachable from) the public website. --- diff --git a/clients/glaztech/reports/2026-06-03-website-security-assessment.md b/clients/glaztech/reports/2026-06-03-website-security-assessment.md index 8b1b2ad..15f4356 100644 --- a/clients/glaztech/reports/2026-06-03-website-security-assessment.md +++ b/clients/glaztech/reports/2026-06-03-website-security-assessment.md @@ -16,6 +16,7 @@ The site stores cardholder data (PAN + CVV) and **all user passwords in plaintex | # | Finding | Severity | |---|---|---| +| C0 | **Internet-facing website connects to SQL Server as `sysadmin`** — a SQLi gives full control of the entire shared instance | Critical (top) | | C1 | Plaintext PAN + stored CVV in DB | Critical | | C2 | All user passwords stored in plaintext; passwords emailed in cleartext | Critical | | C3 | SQL injection via fake `quo()` escaper (incl. payment pages) | Critical | @@ -44,6 +45,33 @@ Re-checked the live system after a report that card processing had moved to a di --- +## C0 (TOP CRITICAL) — The internet-facing website connects to SQL Server as `sysadmin` + +The single most dangerous fact in this engagement (verified 2026-06-03). The public website logs into the database with login **`tom`**, which is a **SQL Server `sysadmin`** (also `securityadmin`, `dbcreator`, `db_owner`) — i.e. **complete control of the entire instance** at `192.168.8.62,3436` (SQL host `GTI-INV-SQL`). `tom` is a **named SQL login** (SQL authentication, created 2018) that is a *member of the `sysadmin` role* — **not** the built-in `sa` and **not** a constrained service account — and its **password is stored in the website's `Web.config`** on the internet-facing server, so anyone who can read that file (via the SQLi, the dev tooling on the box, or a file-disclosure bug) obtains a sysadmin credential outright. That instance is **shared with the internal GTIware PSA** and hosts **46 databases**: every office's production DB (`glaz_prod*`), all `*_archive` databases (years of history), the PDF stores, TimeForce (`qqest`), `gti_samsara`, and the system DBs (`master`, `msdb`). + +Because a SQL injection runs **as the connecting login**, the website's SQLi flaw executes with `sysadmin` rights over that whole instance. Cross-database reach is confirmed live: from a single injectable page on one office's connection we read other offices' card tables (`glaz_prod_phx.dbo.cc_file` = 141, `glaz_prod_den` = 190, `glaz_prod_elp` = 179). + +### Attack chain — low effort, catastrophic result +1. **Guess one website login** (username = the customer account number, enumerable; passwords plaintext, as short as 3 chars; **no lockout/rate-limiting**). +2. **Hit an injectable page** (payment pages build SQL via the non-escaping `quo()` helper). +3. **Inject as `sysadmin`** → total control of the SQL server. + +### What an attacker can do as `sysadmin` (spelled out) +**Steal everything:** dump **all offices' stored cards (full PAN + CVV)** from `cc_file` + the entire `cof_payments_header` history (tens of thousands of card numbers); dump **~9,000+ plaintext passwords** (`web_security`); dump every customer/invoice/order/balance and the multi-year **archive** DBs; read TimeForce/payroll (`qqest`) and anything else on the instance. +**Destroy everything:** `DROP DATABASE`/`DROP TABLE`/`DELETE`/`TRUNCATE` across all 46 databases — wipe live production for **every office** and the archives; or encrypt/drop and ransom (backups are also reachable, so recovery may be impossible). +**Manipulate / commit fraud:** alter invoices, balances, prices, payment records; change account access levels (grant themselves admin); insert fraudulent transactions; falsify or delete audit history. +**Take over the server + network:** enable `xp_cmdshell` to run **OS commands on the SQL server (192.168.8.62)** as the SQL service account — install malware/ransomware, create OS accounts, exfiltrate files, **disable backups and AV**; harvest credentials and **pivot into the wider GTI/Glaztech network** (linked servers, shares, the service account's domain rights); plant persistent SQL backdoors and erase SQL audit trails. + +**Bottom line: one guessed customer password is one SQL-injection away from full theft, destruction, or ransom of the entire GTIware database server — and a foothold into the rest of the network.** + +### Required remediation (do this FIRST) +1. **Stop the website connecting as `sysadmin` immediately.** Give the website a dedicated **least-privilege** SQL login scoped to only the specific tables/views/procs it needs, with **no access to the GTIware databases** (`cc_file`, `web_security`, other offices, archives). Revoke `sysadmin`/`securityadmin`/`dbcreator`. +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. Either move the website to its own database/instance, **or** strictly partition permissions so the public web login **cannot see or reach** the GTIware databases. +3. **Stop storing cardholder data on-prem at all** (best fix): either **call the processor's API directly** (processor-hosted fields / vault — no card data lands on Glaztech systems) or, at minimum, **tokenize the entire process** (store a processor token, never the PAN). **CVV must never be stored — period (PCI Req 3.2).** Any cardholder data that must be at rest has to be **encrypted**. +4. Then: fix the SQL injection (parameterize, remove `quo()`), add login lockout/rate-limiting, hash passwords. + +--- + ## Critical Findings ### C1 — Plaintext PAN and stored CVV (see companion PCI report) @@ -93,13 +121,13 @@ Chaining the findings into the realistic worst case, with difficulty ratings. ## Why the Cards Are Stored, and Where They Flow -**Business purpose — card-on-file invoice auto-pay.** Cards are stored (with an `activate` flag on `cc_file`) so the business can automatically charge customers' open invoices. The proc `i_get_cc_on_file_invoices` joins `invoice` × `cc_file` for active cards with an outstanding, delivered balance; `gt_auto_process_2020.dll` (in `bin`, with stale copies in `Old_bin`/`Old_code\Bin`) is the engine that reads the stored card and bills it via CyberSource. There is no scheduled task — the run is triggered from within the web app (most likely staff-initiated). The large `cof_payments_header` history (e.g. 14,496 rows in Phoenix) is years of these charges. +**Business purpose — card-on-file invoice auto-pay.** Cards are stored (with an `activate` flag on `cc_file`) so the business can automatically charge customers' open invoices. The proc `i_get_cc_on_file_invoices` joins `invoice` × `cc_file` for active cards with an outstanding, delivered balance; `gt_auto_process_2020.dll` / `glaztech_utilities_2020.dll` are the engine that reads the stored card and bills it (currently via CyberSource). **This is GTIware (the internal PSA), staff-operated — NOT the website.** The website has **zero** card-handling code (no `cc_file`/`save_cc_data`/`gt_auto_process` references in its `.aspx`/`.vb`); its quick-pay pages even disclaim saving cards. Saved-card rows are stamped with **staff** usernames (Victoria, Bryce, Diana) and notes like "run card when requested." The large `cof_payments_header` history (e.g. 14,496 rows in Phoenix) is years of these GTIware charges. **Where the full PAN is used.** Only five DB objects reference the full `cc_number`: `save_cc_data`/`save_cc_data1`/`save_cc_data2` (writes) and the `is_cc_active`/`is_cc_on_file` functions. However, **`get_cc_data` is `SELECT *`**, so it also returns the full PAN + CVV whenever a saved card is read for charging — the full number crosses to the app server on every card-on-file charge; the UI only masks the *display*. -**Containment — does NOT spread to other systems.** The Sage 100 ERP DB (`mas_gti`) has **0** procedures referencing `cc_file` or `web_security` — the plaintext cards do **not** propagate into Sage. (Sage's native CC module is in fact **disabled** — `SY_Company.CreditCardEnable = N`, `AR_CustomerCreditCard` = 0 rows — so Sage stores no cards at all and is not a cardholder-data location.) Exposure is **contained to the custom web app's 15 office databases** on SQL `192.168.8.62`. Secondary exposure surfaces: **database backups** (every backup of those DBs contains plaintext PAN + CVV) and **stale on-disk code/data copies** (`Old_bin`, `Old_code`). +**Containment — does NOT spread to other systems.** The Sage 100 ERP DB (`mas_gti`) has **0** procedures referencing `cc_file` or `web_security` — the plaintext cards do **not** propagate into Sage. (Sage's native CC module is in fact **disabled** — `SY_Company.CreditCardEnable = N`, `AR_CustomerCreditCard` = 0 rows — so Sage stores no cards at all and is not a cardholder-data location.) Exposure is **contained to the GTIware databases** (15 office DBs) on `GTI-INV-SQL` (`192.168.8.62`) — the **same SQL instance the public website connects to**, which is exactly how the website's SQLi reaches the card data (see **C0**). Secondary exposure surfaces: **database backups** (every backup of those DBs contains plaintext PAN + CVV) and **stale on-disk code/data copies** (`Old_bin`, `Old_code`). -**Fix preserves the feature.** Migrating card-on-file to the **CyberSource token vault** (store a token; let CyberSource hold the PAN) lets `gt_auto_process` keep auto-billing by token while removing every stored PAN/CVV — and removes the cardholder-data liability from backups. +**Fix preserves the feature.** Have GTIware **call the processor's API directly / use its hosted vault** (no card data stored on-prem), or at minimum **tokenize** (store a processor token; let the processor hold the PAN) — `gt_auto_process` keeps auto-billing by token while removing every stored PAN/CVV (and the backup liability). **CVV must never be stored (PCI Req 3.2)**, and any at-rest cardholder data must be **encrypted**. --- @@ -140,7 +168,7 @@ Web app connects with a **single shared SQL login (`tom`)** that has full read o ## What is Acceptable (balanced view) - **OS patching is current-ish:** Windows Server 2019, build 17763.8755, patched through **May 2026** (supported to 2029) — the OS itself is *not* the weak point. - **Most data access is parameterized** (948 parameterized calls) — the SQLi exposure is a bounded set of concatenated queries, not pervasive. -- **The Sage 100 ERP DB** (`mas_gti`) stores **no** cardholder data — its native CC module is **disabled** (`CreditCardEnable = N`, `AR_CustomerCreditCard` = 0 rows; tokenization columns exist in the schema but are unused). The plaintext exposure is **entirely the custom web app**, not Sage. +- **The Sage 100 ERP DB** (`mas_gti`) stores **no** cardholder data — its native CC module is **disabled** (`CreditCardEnable = N`, `AR_CustomerCreditCard` = 0 rows; tokenization columns exist in the schema but are unused). The plaintext exposure is **entirely GTIware's card-on-file feature** (the internal PSA, staff-operated, storing into databases the website shares) — **not** Sage, and **not** the website's payment pages (which store nothing). The website's role is the *access path* (C0), not the storer. - TLS 1.2 to CyberSource now works (payment outage fixed 2026-06-03). --- diff --git a/clients/glaztech/session-logs/2026-06-03-session.md b/clients/glaztech/session-logs/2026-06-03-session.md index ae398df..cbbfa95 100644 --- a/clients/glaztech/session-logs/2026-06-03-session.md +++ b/clients/glaztech/session-logs/2026-06-03-session.md @@ -120,3 +120,22 @@ Mike reported Glaztech "no longer uses CyberSource, switched to Payrilla (secure **Actions:** updated `clients/glaztech/reports/2026-06-03-website-security-assessment.md` (added "Current State Verified — 2026-06-03" section; corrected two Sage lines from "uses tokenization / materially compliant" to "CC module disabled, 0 stored cards"). Posted public+emailed client comment on **#32378** (id 417040624) reflecting the live, ongoing risk and that Payrilla is not yet implemented on the site. Drafted a further client clarification (the Sage/Payrilla visibility gap) — **pending Mike's go** before posting (would be the 4th #32378 email today). **Open:** confirm with Payrilla which flows actually route through them; investigate the corp `cc_file` anomaly; remediation path reframed to "migrate the website's card-on-file to the chosen processor's token vault, stop writing `cc_file`/`cof_payments_header`, purge plaintext + backups, decommission CyberSource." + +--- + +## Update: 19:32 PT — Tom (dev) reply thread: storage = GTIware, website = sysadmin access vector (TOP CRITICAL) + +Tom (Glaztech's internal IT / **author of the GTIware/GlazGTI PSA**) replied to #32378 asking where the website stores data, stating he stores nothing from the website's online payment system. Investigated and **Tom is correct** — and it surfaced the single worst finding of the engagement. + +- **The website stores NO cards.** Zero `cc_file`/`save_cc_data` references in the site's `.aspx`/`.vb`; the quick-pay pages even carry a disclaimer "Glaz-Tech Industries does not save nor record any card info." The site uses the shared `gt_utilities` namespace (209 refs) for general plumbing only. +- **The cards are written by GTIware** (Tom's PSA): the `cc_file`/`save_cc_data` logic is in compiled libraries `glaztech_utilities_2020.dll` + `gt_auto_process_2020.dll` (deployed in the site's `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 save-a-card workflow. +- **TOP CRITICAL (now C0 in the report): the website connects to the GTIware SQL server as a `sysadmin`.** The site's `Web.config` uses SQL auth `user id=tom` (login id 267, a **named SQL login, member of the `sysadmin` role — NOT the built-in `sa`**, created 2018; password embedded in `Web.config`). The SQL host is **`GTI-INV-SQL` (192.168.8.62,3436)**, shared by the website and GTIware, with **46 databases** (all offices' `glaz_prod*` + `*_archive` + PDF stores + `qqest` TimeForce + `gti_samsara` + system DBs). Because SQLi runs as the connecting login, the website's `quo()` SQL-injection executes as sysadmin. **Cross-DB confirmed live:** from the Tucson connection, read other offices' `glaz_prod_phx.dbo.cc_file` (141), `glaz_prod_den` (190), `glaz_prod_elp` (179). So one guessed website login + the SQLi = full read/write/destroy of the entire GTIware instance + `xp_cmdshell` OS takeover of the SQL server. +- `get_cc_data` is `SELECT * FROM cc_file WHERE acct_no=@acctno` → returns full PAN+CVV; IDOR-shaped on `@acctno`. Other sysadmin logins on the instance: `GTI-INV-SQL\Administrator`, `NT SERVICE\*`, `sa` (enabled), `tom`. + +**Actions:** +- Added **C0** (top critical) to the website security assessment with the full attack tree (steal/destroy/manipulate/OS-takeover) and required remediation (least-privilege web login that cannot see GTIware data; separate/partition the website DB from GTIware; stop storing cards — call processor API directly or tokenize; never store CVV (PCI 3.2); encrypt at rest; fix SQLi + lockout). +- **Corrected both reports' attribution**: storage = GTIware internal PSA (staff-operated), website = access path; Sage CC module disabled (0 cards), not a CHD location. +- Posted **plain-English reply to Tom** on #32378 (public+emailed, comment 417070212): leads with "how we found it" (a website-only review reached internal GTIware card data → that reachability IS the flaw), explains the sysadmin+SQLi chain plainly, lists the four fixes. +- #32378 remains **Waiting on Customer**. + +**Open / next:** Tom to remediate (pull sysadmin login from the site → least-privilege; isolate website DB from GTIware; tokenize / stop storing; never store CVV; fix SQLi + lockout). The corp `cc_file` "Invalid object name" anomaly still unexplained. ACG can execute the quick wins (CVV purge, least-privilege login, debug-off) on request. diff --git a/session-logs/2026-06-03-mspbackups-b2-storage-cleanup.md b/session-logs/2026-06-03-mspbackups-b2-storage-cleanup.md new file mode 100644 index 0000000..9bc3d91 --- /dev/null +++ b/session-logs/2026-06-03-mspbackups-b2-storage-cleanup.md @@ -0,0 +1,48 @@ +# MSP360 / Backblaze B2 storage cleanup — PARKED 2026-06-03 + +## User +- **User:** Mike Swanson (mike) +- **Machine:** GURU-5070 +- **Role:** admin + +## Status: PARKED — bucket is in a safe, stable state. Scheduled purge completes on its own in ~24–48h. + +## Goal +Clean up the legacy shared MSP360 destination (generic B2 bucket `MSPBackups20200311` / "B2Storage") — find data still using it, migrate active users to per-client buckets, remove orphaned data, eventually retire the bucket. + +## Key findings (B2 = ground truth; MSP360 numbers are NOT reliable) +- **MSP360 dashboard storage is a plan-derived internal tally, refreshed daily — NOT a live read of B2.** (`GET /api/Billing`: `CurrentSpaceUsed` "updated once a day", `AverageSpaceUsed` "calculated based on backup plans information".) It does NOT reconcile to physical B2 per-account in either direction (overstates seastman 1.98TB→21GB, mike@ 0.43TB→2GB; understated beckykahn ~0→475GB). +- **Phantom accounts explained:** admin@azcomputerguru.com (15.21TB), vland@airyoptics (12.57TB), etc. show big MSP360 volumes but have **no/*spent* data** in B2 — their data was already deleted by **prior lifecycle purge rules**, and MSP360's counter froze. admin@ is NOT a destination-owner aggregate (bucket is 51TB, not 15.21) — it's a frozen phantom. Confirmed by lifecycle rules present on `MBS-f1885cea…`, `MBS-98f0c6ae…` (vland) etc. with no live data. +- **Generic bucket physical = 51.015 TB**, 11.33M versions, 28 top-level `MBS-/` prefixes. ~48 TB is **active client backups** (the migration set); only ~3–4 TB is genuinely orphaned. Migrating active data to other buckets does NOT save cost (same bytes elsewhere) — only orphan purge does. +- **Dual-destination accounts:** freshness check (newest object ts) decided them — rohrbach/Mike-Think (13.23TB) is **still live on generic today** (not reclaimable); bestmassage frozen 2024-08 (migrated to ACG-PST, reclaimable). +- **Storage accounts (`GET /api/Accounts`):** only 2 — `Local-E` (LocalFS), `MSPBackups` (BackblazeB2, AccountID `ad1b19fd-9350-4fa2-9a07-6200fca14797`). ACG-* names are **destinations** under MSPBackups. Create/modify via API: `POST/PUT /api/Accounts`, `…/CreateDestination`, `…/EditDestination`. Reconcile: all 13 MSP360 destinations have a B2 bucket; `ACG-IX` is an **empty B2 bucket with no MSP360 destination** (orphan/reserved). **No bucket has immutability/object-lock.** + +## Actions TAKEN this session (bucket `MSPBackups20200311`, current state: 21 lifecycle rules, revision 63) +**Scheduled purge (~3.2 TB, completes ~24–48h via B2 lifecycle hide@1/delete@1):** +- Tucson Safety `MBS-1c527291-…/` (0.292TB) — user-authorized +- bestmassage generic `MBS-54a647a3-…/` (2.474TB) — frozen 2024-08; **verified current copy is live in ACG-PST (newest 2026-06-03)** +- Saguaro ×3: `MBS-114c80eb-…/` (L0U6QUN), `MBS-a460695c-…/` (SC-SERVER), `MBS-ff910354-…/` (DGM4C1T) — offboarded +- seastman `…/CBB_GTI-EXCHANGE/` only — user-authorized ("GTI-EXCHANGE can go") +- mike@ `MBS-85b4355a-…/` (2GB webhost), rogue `MBS-4969337d-…/` (~0, no MSP360 user, mdmlaw) + +**Protective rule REMOVALS (non-destructive — un-scheduled erroneous/pending purges):** +- `MBS-a39b0d4c-…/CBB_MIKE-THINK/` — **rohrbach 13.23 TB ACTIVE** — pre-existing purge rule from a prior cleanup; caught before B2's daily pass fired (data confirmed intact). **Active backup was at risk of deletion.** +- `MBS-651e4c79-…/` — diegobuilder (Air Pros), active — same. +- `MBS-c064d061-…/CBB_MAS90SVR/` + my over-broad account-root `MBS-c064d061-…/` — protect MAS90SVR pending Mike's check. + +## OPEN ITEMS (resume here) +1. **HIGH/SAFETY — audit ALL B2 buckets' lifecycle rules for purge rules on ACTIVE accounts.** A prior cleanup endangered rohrbach's 13 TB here; same may exist in ACG-* per-client buckets. Read-only; do this first. +2. **MAS90SVR** — Mike checking status; `CBB_MAS90SVR` rule removed (protected). Decide keep vs purge. +3. **beckykahn / LAB-BECKY (475 GB)** — held; stopped backing up 2026-04-14 (not long-abandoned). Confirm decommissioned before purge (`MBS-20e00bf6-…/`). +4. **rohrbach + diegobuilder** — confirm protective rule removal was correct (almost certainly — both active). Re-addable if intentional. +5. **Post-purge verify (after 2026-06-05):** re-measure `MSPBackups20200311` (expect ~3.2 TB drop), then `lifecycle-remove` the spent rules. +6. **Phantom MSP360 user cleanup (cosmetic):** admin@/vland/etc. via `DELETE /api/Users/{id}/Account` (metadata-only — does NOT touch B2). Fixes the dashboard; frees nothing (data already gone). +7. **Active-user migration (the big project, ~48 TB):** per-client destination + plan repoint (console — Remote Management API is disabled, no API automation) + reseed; only then retire the generic bucket. Not a cost play. + +## Reference / access +- MSP360 API: `https://api.mspbackups.com` (DNS fails locally → pin `52.6.7.137` + SNI). Auth `POST /api/Provider/Login`. Creds: vault `msp-tools/msp360-api.sops.yaml`. **`/Help` = full endpoint docs.** Correct user-data delete = `DELETE /api/Users/{id}?deleteUserData=true` (but blocked on "personal" accounts); computer = `DELETE /api/Users/{userId}/Computers` (body `[{DestinationId,ComputerName}]`). +- B2: skill `.claude/skills/b2/`; account `46f69bc61163`; generic bucketId `b4268f56790bccc671010613`. Purge = `delete-prefix [--allow-account-root] --confirm` (lifecycle, ~24–48h); undo-able only before the daily pass via `lifecycle-remove`. +- Separately pending (earlier today): **Glaztech SBS** MSP360 removal needs the web portal (API blocked by "personal user" guard) — coord todo `db03f8fe`. Grok post-mortem: `docs/session-notes/2026-06-03-claude-postmortem-grok-mspbackups-sbs.md`. + +## Note +Unrelated dev-mode lock `guruconnect/agent/src` (held by this session) is from other work — left as-is. diff --git a/wiki/clients/glaztech.md b/wiki/clients/glaztech.md index 56f9c2c..30072d5 100644 --- a/wiki/clients/glaztech.md +++ b/wiki/clients/glaztech.md @@ -23,10 +23,10 @@ backlinks: [] ## 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. +- **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, In Progress as of 2026-06-03) +- **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) @@ -40,14 +40,15 @@ Multi-site Windows environment (~200 users, 9 locations). Active Directory confi | 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; **doubles as dev workstation** (VS 2015+2022 installed — see Security Posture) | -| SQL backend | SQL Server — 15 per-office databases + Sage 100 + TimeForce | [unverified — Server 2019 assumed, co-located with Glaztech infra] | 192.168.8.62,3436 | — | Login `tom` (creds in site Web.config, NOT vaulted); DBs: glaz_prod (tuc), 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 + mas_gti (Sage 100) + qqest (TimeForce) | +| 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 via gt_auto_process_2020.dll | +| 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 @@ -110,7 +111,7 @@ Note on Priority 1: The "GTIMail No-Reply - Reject Inbound" rule rejects ALL inb - **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. Read-only access for assessment only; do NOT use outside of authorized sessions. +- **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) @@ -120,12 +121,32 @@ Note on Priority 1: The "GTIMail No-Reply - Reject Inbound" rule rejects ALL inb A full read-only security assessment of the Glaztech e-commerce web application and SQL backend was performed 2026-06-03. 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 auth, 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 limited to the 15 custom web-app databases on 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). **Database backups also contain plaintext PANs — cleanup must address backups, not just live data.** +- **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 @@ -142,7 +163,7 @@ 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; a logged-in attacker can UNION-inject full PANs + CVV.** +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 @@ -153,30 +174,31 @@ Used to build concatenated dynamic SQL in payment pages (`ach.aspx.vb`, `quick-p | 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 full read on card + password columns; creds in `Web.config` in cleartext | 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 | High | ### 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()` to UNION-dump `cc_file` → full PAN + CVV for all saved cards in the office, plaintext. **Every compensating control (lockout, password hashing, PAN encryption, parameterized queries) is absent; first failure is last failure.** +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.** -### Remediation Roadmap (Ticket #32378 — In Progress) +### Remediation Roadmap (Ticket #32378 — Waiting on Customer) -**Now (days):** -1. Purge stored CVV (`cc_file.cc_code`, backup-first — needs Tom/Steve explicit sign-off) -2. `debug="false"` + `customErrors="On"`; HTML-encode `gt_errorpage.aspx`; stop echoing exception text to users -3. Remove RealVNC 4.2.8 and stale ScreenConnect v6 -4. Disable TLS 1.0/1.1 on the IIS/SChannel listener +**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):** -5. Hash all passwords (PBKDF2/bcrypt/Argon2); replace email-the-password flow with reset-token flow; force global reset -6. Parameterize all concatenated SQL in payment pages; delete `quo()` -7. Add Secure+HttpOnly cookies, session regeneration on login, login throttling/lockout -8. Migrate card-on-file to the chosen processor's token vault (CyberSource or the new provider — confirm which flows actually route through "Payrilla"); purge/encrypt historical `cc_number` columns; address backups +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 +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:** -9. Separate dev from production; deploy precompiled; remove SDKs/IDE/source from prod host -10. Least-privilege SQL accounts; secret management for Web.config connection strings; TDE at rest; re-scope merchant PCI SAQ after remediation +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 @@ -195,8 +217,9 @@ Obtain a customer login (LOW difficulty — no lockout, guessable username = acc - **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 auto-pay via `gt_auto_process_2020.dll`. Deleting the PANs without a replacement breaks the auto-billing feature. The safe path is CyberSource 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. +- **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. ## Active Work @@ -222,9 +245,12 @@ Waiting on Steve's reply to: 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 — In Progress) +### Website Security Remediation (Ticket #32378 — Waiting on Customer) -Security assessment complete 2026-06-03. Awaiting Mike/Steve direction to begin remediation. See Security Posture section and reports in `clients/glaztech/reports/` for full detail. Key actions queued but not yet executed (require client sign-off): +Security assessment complete 2026-06-03. 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 @@ -250,6 +276,8 @@ Message trace confirmed shannon@glaztech.com receives no MailProtector digests a - 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 ## History Highlights @@ -260,7 +288,8 @@ Message trace confirmed shannon@glaztech.com receives no MailProtector digests a - **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** — 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: full PANs + CVV plaintext, ~9,000+ plaintext passwords, SQL injection via `quo()` helper in payment pages, reflected XSS, debug mode on, dev workstation on prod, RealVNC 4.2.8, TLS 1.0/1.1 listener, single shared SQL login. Exposure contained to custom web-app DBs (not Sage 100 which tokenizes). Two reports created. Ticket #32378 opened and left In Progress for remediation. 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. +- **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**. ## Backlinks diff --git a/wiki/index.md b/wiki/index.md index d1894fb..55e2fb5 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -25,7 +25,7 @@ Run `/wiki-lint` to check for stale entries and broken backlinks. | [ACG Internal Infrastructure](clients/internal-infrastructure.md) | ACG's own hosting infra — Neptune Exchange (cert expires 2026-05-31, DkimSigner disabled), IX server, Cloudflare tunnel workaround, ACG M365 tenant gaps | 2026-05-24 | | [BirthBiologic](clients/birth-biologic.md) | Bio/healthcare; BB-SERVER (WS2016) GuruRMM enrolled; Datto→SharePoint migration incomplete; M365 apps partially consented | 2026-05-24 | | [CryoWeave](clients/cryoweave.md) | Custom cryogenic cable assemblies; cPanel on IX; website redesign + SEO project in progress; Syncro ID not documented | 2026-05-24 | -| [Glaz-Tech Industries](clients/glaztech.md) | ~200 users, 9 locations; prepaid ~22.25 hrs; web server WWW (192.168.8.72 / 65.113.52.88) — IIS 10/VB.NET e-commerce; CRITICAL security posture (plaintext PANs+CVV, plaintext passwords, SQLi, XSS); apex 404 fixed + payment TLS fixed 2026-06-03; #32378 open for PCI remediation; M365 no MFA; SCL bypass rules for vendor DMARC + MailProtector digests | 2026-06-03 | +| [Glaz-Tech Industries](clients/glaztech.md) | ~200 users, 9 locations; prepaid ~22.25 hrs; web server WWW (192.168.8.72 / 65.113.52.88) — IIS 10/VB.NET e-commerce; CRITICAL security posture: website connects to GTI-INV-SQL as sysadmin (login `tom`, named SQL login, C0 top finding) + plaintext PANs+CVV (stored by GTIware PSA, not website) + plaintext passwords + SQLi via `quo()` + XSS; apex 404 fixed + payment TLS fixed 2026-06-03; #32378 Waiting on Customer (assessment + reports delivered, Tom replied); M365 no MFA; SCL bypass rules for vendor DMARC + MailProtector digests | 2026-06-03 | | [Grabb & Durando Law Office](clients/grabb-durando.md) | Personal injury law firm; GND-SERVER GuruRMM enrolled; AI demand review app scoped ($4K–$7K); website migration pending; plaintext DB password in README needs vaulting | 2026-05-24 | | [Pavon](clients/pavon.md) | Former/archive client; GeoVision NVR surveillance; OwnCloud at 172.16.3.22 backed by Uranus; cron stacking fixed; Nextcloud migration deferred 3–6 months | 2026-05-24 | | [Rednour Law Offices](clients/rednour.md) | Law firm; M365 rednourlaw.com (tenant 4a4ca18a) fully onboarded 2026-05-31; all 5 ComputerGuru SPs consented; no MDE license; 3 workstations GuruRMM enrolled (FRONTDESKRECEPT/LEGALASST/REDNOURCARRIEVI); Carla Skinner renamed from Emma; prior MSP agents (ScreenConnect/Splashtop/Datto) still present; shared-drive access for Nick Pafford deferred | 2026-06-02 |