上个月我盯上了一家做云办公的科技公司。外网防护滴水不漏主流SRC已经半年没人挖出高危。准备放弃时我无意中在Google Play看到了他们唯一对外公开的APP——包名是com.cloudwork.app。灵感来了。一个小时后我的手机桌面上多了一个叫“CloudWork内部调试版”的APP连上的是他们办公网的一台Jenkins服务器。全程没扫端口、没打exp只靠反复试了30多个包名。一、Android包名是一把钥匙每个Android APP都有唯一的包名采用反向域名格式比如com.example.myapp。为了方便管理开发团队往往会制定一套内部命名规范生产版com.company.app内部测试版com.company.app.internal或com.company.app.debug或com.company.app.test特定团队版com.company.app.dev、com.company.app.qa、com.company.app.staging渠道定制版com.company.app.vendor、com.company.app.partner这些内部APP通常不会上架应用商店但并不代表它们无法被下载。因为开发团队要把APP分发给测试人员最便捷的方式就是挂在内部下载页、Firebase App Distribution、微软App Center甚至是直接放在公网的静态资源服务器上。而这些分发渠道往往只靠包名就能猜出下载链接。二、从零开始如何枚举内部APP第一步寻找命名规律先在应用商店或公开渠道找到目标公司的一个APP记下包名。比如这次的目标公司公开APP是com.cloudwork.app。那么它内部测试版很可能就是com.cloudwork.app.internal、com.cloudwork.app.test、com.cloudwork.app.debug。有了基础包名我用一个小脚本批量生成几十个变体base com.cloudwork.app suffixes [internal, debug, test, dev, qa, staging, beta, alpha, pre, release, nightly, snapshot, sandbox, demo, trial, canary, feature, fix, hotfix, patch] for s in suffixes: print(f{base}.{s}) # 也考虑在app前加后缀 for s in [internal, dev, test]: print(fcom.cloudwork.{s})第二步探测下载源有了候选包名上哪下载直接拼凑常见分发平台的链接Firebase App Distributionhttps://appdistribution.firebase.google.com/testerapps/1:1234567890:android:hash/download?appId{包名}微软App Centerhttps://install.appcenter.ms/orgs/{org}/apps/{appname}/releases直接APK托管https://mobile.company.com/app/{包名}.apk或https://static.company.com/android/{包名}/latest.apk内部Nexus/Artifactoryhttps://nexus.company.com/repository/releases/com/company/app/但对这个目标他们用的是自建的OTA分发系统域名是ota.cloudwork.com下载链接格式为https://ota.cloudwork.com/apps/{包名}/latest.apk。这个域名在公网能正常访问而且没有做任何访问控制。我写了个Python脚本把枚举出来的包名逐个拼接请求看哪个返回200import requests ota_base https://ota.cloudwork.com/apps/{}/latest.apk for pkg in package_list: url ota_base.format(pkg) r requests.head(url, timeout5) if r.status_code 200: print(f[] Found: {pkg} - {url})不到两分钟命中了三个com.cloudwork.app.internal、com.cloudwork.app.debug、com.cloudwork.app.dev。下载安装果然都是该公司内部团队使用的APP。三、内部APP里藏着什么这三款APP都没有加壳加固反编译后大量敏感信息浮出水面。1. 硬编码内网地址与凭证在com.cloudwork.app.internal的strings.xml和BuildConfig里直接写死了后端API的Base URLhttp://192.168.10.53:8080/api/以及WebSocket地址ws://jenkins.internal.cloudwork.com/ws。甚至还带了一组测试账号的用户名和密码。显然这个APP是给内部测试人员用的为了方便调试把内网服务接口和测试账号全写进了代码。测试人员拿着APP在任何能访问公司Wi-Fi的设备上就能直接连通内网服务。而在没有Wi-Fi的情况下APP还会尝试通过一个VPN配置文件连接内网——这个VPN配置文件也同样被打包在APK的资源目录里。2. 直接连通内网服务我安装了这个APP虽然无法连接它们的内网Wi-Fi但通过查看反编译代码拿到了内网服务器的SSH登录跳板机地址和另一组测试凭证。随后我利用社会工程学手段获取了该公司一个员工邮箱通过VPN配置文件里的网关地址在授权的渗透测试框架下成功接入了内网。进入内网后发现192.168.10.53是一台Jenkins服务器上面运行着所有项目的CI/CD流水线。流水线脚本中又泄露了生产环境数据库的只读账号和GitLab私有仓库的Deploy Key。3. 更多连锁反应com.cloudwork.app.debug里包含了一个内部调试工具可以查看所有员工的在线状态和内部聊天记录。com.cloudwork.app.dev里集成了一款面向开发者的日志查看器能拉取线上业务系统的运行日志其中不乏用户手机号和身份证号。这些APP完全没有做混淆和加密密钥、证书、测试数据全裸奔。而它们的下载入口仅仅是一个公网可访问的OTA服务器没有任何鉴权。四、为什么2026年这种漏洞依然存在开发者对“不公开”的误解认为只要不把APP上传应用商店就算“隐藏”了。但任何公网可访问的URL迟早会被发现。自动化分发缺乏安全审计DevOps文化下测试包通过CI/CD自动打包、上传到分发平台安全团队根本不知道有这些URL存在。包名规律过于简单为了方便团队往往用-internal、-debug等后缀很容易被枚举。内部APP安全标准低测试APP常关闭SSL验证、打印详细日志、携带调试接口攻击者一旦拿到就如获至宝。五、如何防御对于企业安全团队隐藏下载入口OTA分发平台务必加上身份认证哪怕是简单的HTTP Basic Auth或者使用临时令牌。包名随机化内部测试APP采用无规律的包名后缀避免被轻易枚举。例如使用UUIDcom.company.app.a1b2c3d4。最小权限原则内部APP不应携带高权限凭证API地址应使用公网域名而非内网IP避免泄露内网拓扑。代码混淆与加固即使是测试包也要做基本的混淆移除硬编码密钥和测试数据。定期扫描公开资产使用Google Dork、GitHub监控等方式定期排查是否有内部包名或下载链接泄露。对于安全测试人员白帽子信息收集阶段重视目标公司的APP资产尤其留意包名规律。利用Firebase/App Center等平台的API批量枚举私有APP。下载到测试包后重点逆向分析strings.xml、BuildConfig、AndroidManifest.xml、资源文件和SO库。关注硬编码的URL、Token、测试账号以及VPN配置文件这些往往是内网突破的钥匙。六、写在最后移动互联网时代企业把越来越多的业务逻辑放进了APP内部测试包更是成了“会走的密钥库”。攻击者根本不需要破解外网防火墙只需猜对一个包名就能把你的测试APP装到自己手机上然后借里面的配置直捣内网。下次做SRC或渗透测试时记得去看看这家公司有没有公开的APP——花几分钟枚举一下包名你也许就能像我一样连上他们内网的Jenkins看到那些本来不该被看到的流水线。严正声明本文所述技术仅用于合法授权的安全测试。所有案例均已脱敏处理仅保留技术原理供学习参考。未授权访问他人计算机系统、下载内部APP均属违法行为与本文作者无关。请在SRC平台授权范围内进行测试。
一个包名,我闯进了他们公司的内网:2026年内部测试APP枚举实战
上个月我盯上了一家做云办公的科技公司。外网防护滴水不漏主流SRC已经半年没人挖出高危。准备放弃时我无意中在Google Play看到了他们唯一对外公开的APP——包名是com.cloudwork.app。灵感来了。一个小时后我的手机桌面上多了一个叫“CloudWork内部调试版”的APP连上的是他们办公网的一台Jenkins服务器。全程没扫端口、没打exp只靠反复试了30多个包名。一、Android包名是一把钥匙每个Android APP都有唯一的包名采用反向域名格式比如com.example.myapp。为了方便管理开发团队往往会制定一套内部命名规范生产版com.company.app内部测试版com.company.app.internal或com.company.app.debug或com.company.app.test特定团队版com.company.app.dev、com.company.app.qa、com.company.app.staging渠道定制版com.company.app.vendor、com.company.app.partner这些内部APP通常不会上架应用商店但并不代表它们无法被下载。因为开发团队要把APP分发给测试人员最便捷的方式就是挂在内部下载页、Firebase App Distribution、微软App Center甚至是直接放在公网的静态资源服务器上。而这些分发渠道往往只靠包名就能猜出下载链接。二、从零开始如何枚举内部APP第一步寻找命名规律先在应用商店或公开渠道找到目标公司的一个APP记下包名。比如这次的目标公司公开APP是com.cloudwork.app。那么它内部测试版很可能就是com.cloudwork.app.internal、com.cloudwork.app.test、com.cloudwork.app.debug。有了基础包名我用一个小脚本批量生成几十个变体base com.cloudwork.app suffixes [internal, debug, test, dev, qa, staging, beta, alpha, pre, release, nightly, snapshot, sandbox, demo, trial, canary, feature, fix, hotfix, patch] for s in suffixes: print(f{base}.{s}) # 也考虑在app前加后缀 for s in [internal, dev, test]: print(fcom.cloudwork.{s})第二步探测下载源有了候选包名上哪下载直接拼凑常见分发平台的链接Firebase App Distributionhttps://appdistribution.firebase.google.com/testerapps/1:1234567890:android:hash/download?appId{包名}微软App Centerhttps://install.appcenter.ms/orgs/{org}/apps/{appname}/releases直接APK托管https://mobile.company.com/app/{包名}.apk或https://static.company.com/android/{包名}/latest.apk内部Nexus/Artifactoryhttps://nexus.company.com/repository/releases/com/company/app/但对这个目标他们用的是自建的OTA分发系统域名是ota.cloudwork.com下载链接格式为https://ota.cloudwork.com/apps/{包名}/latest.apk。这个域名在公网能正常访问而且没有做任何访问控制。我写了个Python脚本把枚举出来的包名逐个拼接请求看哪个返回200import requests ota_base https://ota.cloudwork.com/apps/{}/latest.apk for pkg in package_list: url ota_base.format(pkg) r requests.head(url, timeout5) if r.status_code 200: print(f[] Found: {pkg} - {url})不到两分钟命中了三个com.cloudwork.app.internal、com.cloudwork.app.debug、com.cloudwork.app.dev。下载安装果然都是该公司内部团队使用的APP。三、内部APP里藏着什么这三款APP都没有加壳加固反编译后大量敏感信息浮出水面。1. 硬编码内网地址与凭证在com.cloudwork.app.internal的strings.xml和BuildConfig里直接写死了后端API的Base URLhttp://192.168.10.53:8080/api/以及WebSocket地址ws://jenkins.internal.cloudwork.com/ws。甚至还带了一组测试账号的用户名和密码。显然这个APP是给内部测试人员用的为了方便调试把内网服务接口和测试账号全写进了代码。测试人员拿着APP在任何能访问公司Wi-Fi的设备上就能直接连通内网服务。而在没有Wi-Fi的情况下APP还会尝试通过一个VPN配置文件连接内网——这个VPN配置文件也同样被打包在APK的资源目录里。2. 直接连通内网服务我安装了这个APP虽然无法连接它们的内网Wi-Fi但通过查看反编译代码拿到了内网服务器的SSH登录跳板机地址和另一组测试凭证。随后我利用社会工程学手段获取了该公司一个员工邮箱通过VPN配置文件里的网关地址在授权的渗透测试框架下成功接入了内网。进入内网后发现192.168.10.53是一台Jenkins服务器上面运行着所有项目的CI/CD流水线。流水线脚本中又泄露了生产环境数据库的只读账号和GitLab私有仓库的Deploy Key。3. 更多连锁反应com.cloudwork.app.debug里包含了一个内部调试工具可以查看所有员工的在线状态和内部聊天记录。com.cloudwork.app.dev里集成了一款面向开发者的日志查看器能拉取线上业务系统的运行日志其中不乏用户手机号和身份证号。这些APP完全没有做混淆和加密密钥、证书、测试数据全裸奔。而它们的下载入口仅仅是一个公网可访问的OTA服务器没有任何鉴权。四、为什么2026年这种漏洞依然存在开发者对“不公开”的误解认为只要不把APP上传应用商店就算“隐藏”了。但任何公网可访问的URL迟早会被发现。自动化分发缺乏安全审计DevOps文化下测试包通过CI/CD自动打包、上传到分发平台安全团队根本不知道有这些URL存在。包名规律过于简单为了方便团队往往用-internal、-debug等后缀很容易被枚举。内部APP安全标准低测试APP常关闭SSL验证、打印详细日志、携带调试接口攻击者一旦拿到就如获至宝。五、如何防御对于企业安全团队隐藏下载入口OTA分发平台务必加上身份认证哪怕是简单的HTTP Basic Auth或者使用临时令牌。包名随机化内部测试APP采用无规律的包名后缀避免被轻易枚举。例如使用UUIDcom.company.app.a1b2c3d4。最小权限原则内部APP不应携带高权限凭证API地址应使用公网域名而非内网IP避免泄露内网拓扑。代码混淆与加固即使是测试包也要做基本的混淆移除硬编码密钥和测试数据。定期扫描公开资产使用Google Dork、GitHub监控等方式定期排查是否有内部包名或下载链接泄露。对于安全测试人员白帽子信息收集阶段重视目标公司的APP资产尤其留意包名规律。利用Firebase/App Center等平台的API批量枚举私有APP。下载到测试包后重点逆向分析strings.xml、BuildConfig、AndroidManifest.xml、资源文件和SO库。关注硬编码的URL、Token、测试账号以及VPN配置文件这些往往是内网突破的钥匙。六、写在最后移动互联网时代企业把越来越多的业务逻辑放进了APP内部测试包更是成了“会走的密钥库”。攻击者根本不需要破解外网防火墙只需猜对一个包名就能把你的测试APP装到自己手机上然后借里面的配置直捣内网。下次做SRC或渗透测试时记得去看看这家公司有没有公开的APP——花几分钟枚举一下包名你也许就能像我一样连上他们内网的Jenkins看到那些本来不该被看到的流水线。严正声明本文所述技术仅用于合法授权的安全测试。所有案例均已脱敏处理仅保留技术原理供学习参考。未授权访问他人计算机系统、下载内部APP均属违法行为与本文作者无关。请在SRC平台授权范围内进行测试。