A Party-Invite Phish, Watched Live: a Repointable QR Code, an Operator Panel, and Signatures
Written by Claude Opus 5.5 from prompts, source material, and direction provided by David E. Weekly, who reviewed it before publication. Written by the model as an agent during the live incident response, under David’s direction and with his review. The incident, the honeypot run (David entered the credentials himself in an isolated browser), and the investigative decisions are David’s; the technical analysis and the prose are the model’s. Model: Claude Opus 5.5 (Anthropic). Disclosure level: ai-generated.
[.] in place of dots, hxxps in place of https) so nothing here is clickable by accident. Do not reassemble or visit them outside an isolated analysis environment.
Summary
On 2026-09-22 a Partiful-styled party invitation (“Your name is on the list. ✨🥂 We’re delighted to have you join us. 🎉”) arrived from the genuine Gmail account of someone I know, blind-copied to that account’s contacts. It is the same delivery pattern as the Punchbowl e-card ten days earlier and the Nyasher bid-proposal lure in July: a real account, so SPF, DKIM and DMARC all pass, and a single link.
Behind the link is a different kit from both. Where VoidProxy reverse-proxied Google’s real sign-in and Nyasher streamed a remote browser, this is a plain PHP copy of Google’s sign-in page with an operator panel: the victim types an email and a password, then waits on a “Processing” page while someone, or something, on the other end tries the password against Google and decides which page the victim sees next.
Three findings are worth taking away:
- The first hop is a dynamic QR code on the
scan[.]pageservice, whose destination the operator can change at any time. Taking down the phishing server leaves every link already delivered able to be repointed. The QR record is the thing to kill. - The kit’s session ids are timestamps. Its fake Cloudflare “Ray ID” and its
session_idvalues are PHPuniqid()output, which encodes the Unix time of each request. Every victim’s session id records the second they arrived. - A honeypot run measured the operator. A wrong password got a “Wrong password” page back in about 12 seconds. A correct password for a throwaway test account led to a sign-in from a US consumer VPN on a Windows machine named
DESKTOP-1C3NAFSabout a minute later, and a second appearance after the first password change.
Delivery
The message was sent from inside the compromised account, not spoofed:
| Check | Result |
|---|---|
| SPF | pass (209.85.220.41, Google outbound mail-sor-f41.google.com) |
| DKIM | pass (d=gmail.com, s=20251104) |
| DMARC | pass (header.from=gmail.com) |
| ARC | pass |
The signs of a taken-over account are the same as last time: a Gmail-composed Message-ID (CA…@mail.gmail.com), To: undisclosed-recipients:; with the real recipients in Bcc, and genuine brand images hotlinked from the brand’s own servers (assets.getpartiful.com/images/emails/themes/light/…, and a generic placeholder poster from partiful-posters.imgix.net/save-2). The template has visible mistakes: “Hey [sender’s name] Invited you to” has the sender’s name where the recipient’s should be, a stray <span class="gmail_default"> shows the HTML was pasted into Gmail’s compose window, and the event has a time (“6:00 ET”) but no place (“RSVP to see location”).
The most useful single check for mail filters: a genuine Partiful invitation is sent by Partiful. A real invite in the same mailbox came from invites@partiful-mail[.]com. Partiful’s email template and images arriving from a personal gmail.com address is the signature of this lure, and the same test (brand assets, but not the brand’s sending domain) caught the Punchbowl one.
Every clickable element (logo, poster, “Going”, “Maybe”, “Can’t Go”, “RSVP”, “View event page”) points at the same URL.
The chain
hxxps://scan[.]page/p/sQc5Ez dynamic QR-code redirect
-> hxxps://vmi3569630[.]contaboserver[.]net/nb/ fake Cloudflare "Checking your browser"
-> /nb/pages/login.php?session_id=sess_… real Cloudflare Turnstile, then email
-> /nb/pages/password.php?session_id=… password
-> /nb/pages/waiting.php?session_id=… "Processing", polling the operator
-> /nb/pages/<chosen by operator>.php?session_id=… observed: wrong_password
The redirect can be repointed
scan[.]page is a QR-code and short-link service. Its public API returns the record behind the link:
{
"status": "DRAFT",
"id": 21965084,
"type": "url",
"data": {
"url": "https://vmi3569630.contaboserver.net/nb",
"status": true,
"requires_password": false
}
}
The destination is a field the account owner can edit. If the phishing server is taken down, the operator can point record 21965084 at a new server, and every copy of the email already sitting in inboxes starts working again. For anyone filing reports on a campaign like this, the redirect service is the report that ends the campaign; the hosting provider’s report ends one server.
No domain, no CDN
The phishing server is a Contabo VPS reached by its default hostname, vmi3569630[.]contaboserver[.]net (213.136.77.156, AS51167, Germany). No domain was registered and nothing sits in front of it, so unlike both earlier campaigns there is no registrar to report to, and the origin address is in plain view. The server’s root page is the stock “CyberPanel Installed” placeholder, responses carry x-powered-by: CyberPanel-OLS/2.5.0, and its Let’s Encrypt certificate was issued 2026-09-10, twelve days before the email went out. The kit lives in /nb/.
Two “prove you’re human” steps, one of them fake
/nb/ serves a copy of Cloudflare’s old “Checking your browser before accessing…” page, with its own stylesheet at /nb/Antibot/cf.css, the target brand filled in as the literal text Checking your browser before accessing google., and a five-second JavaScript redirect. The redirect is wrapped in token obfuscation that ships with its own explanatory comments (// Obfuscated redirection snippet, // dummy computation (equals 3)).
The sign-in page then shows a real Cloudflare Turnstile widget (sitekey 0x4AAAAAAEu3is8SouVbNc8V) over the form. Its success callback only hides the overlay:
function onTurnstileSuccess(token) {
document.getElementById('captcha-overlay').style.display = 'none';
}
The token is never checked by the server, so the whole credential form is in the HTML any client receives: a plain curl gets the complete phishing page. Turnstile did fail a browser under automation control (error 600010, which Cloudflare documents as a generic challenge failure), so it still turns away some automated scanners, but anything that reads the page source rather than rendering it walks straight past.
The Ray ID and the session id are timestamps
The fake Cloudflare page prints a Ray ID, and links on to a session_id. From one request:
Ray ID: 6ab2b151abf30
session_id: sess_6ab2b151abf205.66329856
These are PHP uniqid() values. uniqid() returns 13 hex digits (eight for Unix seconds, five for microseconds), and uniqid('sess_', true) returns 14 hex digits, a dot, and eight more digits. Both begin 6ab2b151abf, and 0x6ab2b151 is 1790095697, which is 2026-09-22 16:48:17 UTC: the moment of that request. The same decoding matched the time of each of three separate visits.
So the “Ray ID” is the kit’s own clock printed a second time, and every session id records when its victim arrived. For defenders that is a detection handle (a Cloudflare-styled page whose Ray ID decodes to the current Unix time is not Cloudflare), and for anyone who later gets hold of the kit’s victim table it dates every entry.
An operator panel decides what the victim sees next
Every page reports in every two or three seconds:
setInterval(function () {
fetch('../update_online.php?session_id=sess_…');
}, 2000);
which is how a panel shows its operator who is on the page right now. Both form submits also wait on a fake two-second spinner before posting. After the password, the victim is sent to waiting.php, which asks the server what to do next:
setInterval(function () {
fetch('../poll_status.php?session_id=' + sessionId)
.then((r) => r.json())
.then((data) => {
if (data.status && data.status !== 'waiting') {
window.location.href = data.status + '.php?session_id=' + sessionId;
}
});
}, 2000);
poll_status.php answers {"status":"waiting"} until the operator acts, and then answers with the name of the next page. The page list is not fixed in the client, which is why about twenty guesses at a code-entry page (otp, 2fa, code, verify, challenge, authenticator, push, approve and others) all returned 404: the ones that exist are only reached when the panel names them.
This is the same general design as the manually operated panels Push Security described in May 2026 (Doko’s Panel), where the operator accepts each visitor and moves them between pages by hand. The endpoint names here do not match that write-up, and no public report found for this post names update_online.php, poll_status.php or wrong_password.php.
The kit is not a copy of Google’s live page. There is no traffic to any Google server while a victim is on it, none of the Google artifacts a reverse proxy passes through (__Host-GAPS, x-auto-login, the boq-identity sign-in JavaScript), and its stylesheet points at nine Google Sans font files by a wrong relative path (res/css/res/fonts/…), all of which 404. The page renders in Arial, which is the cheapest visual tell a careful victim gets.
The honeypot run
The credentials were typed by hand into a separate, clean browser profile controlled over the Chrome DevTools protocol, so every request was recorded. The account was a throwaway Gmail created for this purpose. Times are UTC.
| Time | What happened |
|---|---|
| 16:58:58 | Wrong password submitted; the server redirects to waiting.php |
| 16:59:00 | poll_status.php returns {"status":"waiting"} |
| 16:59:10 | The poll response changes; the browser goes to wrong_password.php, a faithful copy of Google’s “Wrong password. Try again…” page with a working retry form. About 12 seconds from submit to verdict. |
| ~17:03 | The account’s real password is submitted through the retry form; back to waiting.php |
| ~17:04 | Google records a new sign-in to the account: Windows, DESKTOP-1C3NAFS, Google Chrome, from 2a0e:d785:4001:6ced:fa89:c551:92f8:78a5 |
| 17:04:53 | The fake victim is still on “Processing”. The operator has the account and never moves the victim on. |
| ~17:06 | The device is signed out and the password changed |
| ~17:07 | The same device shows activity at about 17:06:45, after the change, and is signed out a second time; it did not return |
The sign-in address belongs to a consumer VPN service (AS137409, registered as “VPN Consumer Los Angeles”; Google placed it in Texas). The phishing server is on Contabo’s network in Germany, so the password traveled from the kit to the operator’s own machine and was used there through a US exit address. Choosing a US exit is consistent with trying to look less unusual to Google for American victims; the run cannot show intent.
What the run shows:
- The kit checks passwords against Google within seconds. The run cannot tell whether a person clicked “wrong” in a panel or a script tried the login.
- A correct password becomes a working session in about a minute.
DESKTOP-1C3NAFSis the operator’s machine name. It is a default Windows name and identifies no one on its own, but it is stable for one machine, so a match in another campaign’s sign-in alerts would connect the two.
What it does not show:
- What happens when the account has a second factor. The test account had no 2-Step Verification, so Google did not challenge the operator and the operator never had to send the victim to a code page. Whether the panel has code-entry or “approve on your phone” pages is open.
- Whether the operator’s session survived the first password change, or they signed in again afterwards. The device appeared again about a minute after the change. Either way, the lesson for victims is the same: check the device list again after changing the password, not only before.
How this compares with the last two
| Nyasher (July) | VoidProxy (Sept 12) | This (Sept 22) | |
|---|---|---|---|
| Lure | Bid-proposal PDF | Punchbowl “save the date” | Partiful invite |
| Delivery | Compromised Gmail, Bcc to a mailing list | Compromised Gmail, Bcc to contacts | Compromised Gmail, Bcc to contacts |
| First hop | Framer page | Week-old .cfd domain |
Repointable QR redirect |
| Hosting | Cloudflare Workers, Cloudflare-fronted server | Cloudflare-fronted VPS | Bare VPS, no domain, no CDN |
| Credential page | Remote browser streamed over WebSocket | Live reverse proxy of Google | Static PHP copy with operator panel |
| Beats code-based 2FA | Yes, by design | Yes, by design | Unknown |
The front of all three is the same: a real account, a social or business lure built from genuine brand assets, one link, and a “prove you’re human” step. The machinery behind the link differs every time, so these are different kits, and nothing here connects the operators.
Detection and hunting
Web and proxy:
- Paths:
/pages/login.php?session_id=sess_,/pages/password.php,/pages/waiting.php,/pages/wrong_password.php,/update_online.php?session_id=,/poll_status.php?session_id=,/Antibot/cf.css. - Session id format:
sess_[0-9a-f]{14}\.[0-9]{8}, whose first eight hex digits decode to a Unix time within seconds of the request. - A repeating
GET …/update_online.php?session_id=…every 2 to 3 seconds from a page titled “Sign in - Google” on a non-Google host. - A page titled
Just a moment...containingChecking your browser before accessing google.(lowercase brand, no domain) and a “Ray ID” of exactly 13 hex digits that decodes to the current time. Real Cloudflare Ray IDs are 16 hex digits. - Turnstile sitekey
0x4AAAAAAEu3is8SouVbNc8Von a page titled “Sign in - Google”. - Favicon path
res/img/fav435vsdvge5.png; requests forres/css/res/fonts/GoogleSans-*.woff2that 404. - The comment strings
// Obfuscated redirection snippetand// dummy computation (equals 3).
Mail:
- Partiful (or Punchbowl, or any invitation service) template and images from a personal
gmail.comsender rather than the service’s own sending domain (partiful-mail[.]comfor Partiful). To: undisclosed-recipients:;, a Gmail-composedMessage-ID, and every link in the message pointing at one short-link or QR-redirect URL.
Identity:
- A Google sign-in from a consumer-VPN or hosting network within minutes of a visit to an unfamiliar sign-in page, from a device named
DESKTOP-plus seven characters that the user does not own.
If you entered your password
- Change the password.
- Open Google’s device list (Security, then Your devices), sign out anything you do not recognize, and look again a few minutes later. In this run the operator’s device appeared again after the first change.
- Check recovery email and phone, Gmail forwarding and filters, “Send mail as” addresses, and third-party apps with account access. These let an attacker back in after a password change.
- Look in Sent for messages you did not write. The account that sent this lure was being used to reach its owner’s contacts.
- Add a passkey or security key. The Punchbowl run showed a passkey stopping a kit that relays real-time codes; nothing in this kit can relay one.
Reports
Emailed abuse reports went on 2026-09-22 to the QR service (asking that record 21965084 be disabled), to Contabo (the server), and to the VPN provider (the sign-in address and time window, with a request to keep logs). Reports through Cloudflare’s and Google Safe Browsing’s web forms cover the Turnstile sitekey and the URLs. The owner of the sending account has been told. As of 20:23 UTC on 2026-09-22, the QR record still pointed at the server and the server was still serving the kit.
Indicators (defanged)
- Redirect:
hxxps://scan[.]page/p/sQc5Ez(QR record id21965084) - Server:
vmi3569630[.]contaboserver[.]net,213.136.77.156,2a02:c207:2356:9630::1(Contabo, AS51167) - Kit paths:
/nb/,/nb/index.php,/nb/Antibot/cf.css,/nb/pages/login.php,/nb/pages/password.php,/nb/pages/waiting.php,/nb/pages/wrong_password.php,/nb/update_online.php,/nb/poll_status.php - Turnstile sitekey:
0x4AAAAAAEu3is8SouVbNc8V - Operator sign-in:
2a0e:d785:4001:6ced:fa89:c551:92f8:78a5(AS137409), WindowsDESKTOP-1C3NAFS, Chrome - Lure: Partiful-styled invite, subject “Your name is on the list. ✨🥂 We’re delighted to have you join us. 🎉”, Bcc blast from a compromised Gmail account
References
- Push Security, Inside a phishing panel used by ShinyHunters and BlackFile (May 2026) — pushsecurity.com
- PHP manual,
uniqid— php.net - Cloudflare, Turnstile client-side error codes — developers.cloudflare.com
- Earlier posts: Nyasher, VoidProxy