别再只看 Activity!新手也能看懂的 Android Service 安全解析

别再只看 Activity!新手也能看懂的 Android Service 安全解析

🚨 Android Service 组件的安全风险详解

本文旨在帮助 Android 渗透新手理解:导出型 Service 组件可能带来的安全风险,如何定位、分析与防护。


🌟 如何快速定位有问题的Service?

一、定位service位置

AndroidManifest.xml 中搜索<service

 <service
     android:name=".MyService"
     android:exported="true" />
  • 查找android:exported="true"是否存在,存在则表示该 Service 可被其他 App 调用
  • 是否有android:permission 代表有权限校验,没有代表缺失,需要看代码是否有校验。

二、源码分析是否存在校验

1、使用工具反编译

此处以Jadx为例,检查源码,按下面可跳转具体位置

图片[1]-别再只看 Activity!新手也能看懂的 Android Service 安全解析-极客星球

2、源代码结构示例

 public class EMChatService extends Service {
     ...
     public IBinder onBind(Intent intent) {
         ...
     }
     public int onStartCommand(Intent intent, int i, int i2) {
         ...
     }
 ​
 }

3、查看重点方法

检测下面两个方法:

正常代码示例

onStartCommand()onBind() 中:

  • 安全做法: 
if (PermissionChecker.checkCallingPermission(...) != PERMISSION_GRANTED) {
     stopSelf();
     return START_NOT_STICKY;
 }
 ​
 public int onStartCommand(Intent intent, int flags, int startId) {
     if (Binder.getCallingUid() != Process.myUid()) {
         stopSelf(); // 非本 App 启动,直接终止
         return START_NOT_STICKY;
    }
    ...
 }
 public IBinder onBind(Intent intent) {
     if (Binder.getCallingUid() != Process.myUid()) {
         return null; // 拒绝绑定
    }
     return this.mBinder;
 }
  • 危险信号:
    • 没有任何调用者检查,直接执行逻辑;
    • intent.getExtras()intent.getAction() 等参数直接操作;
    • 返回 Binder 对象供调用方使用。

🧪 ADB验证

📌 测试 EMChatService 是否可被任意启动

 adb shell am startservice -n com.example.targetapp/com.hyphenate.chat.EMChatService
  • 如果该命令返回: Starting service: Intent { cmp=com.example.targetapp/com.hyphenate.chat.EMChatService }且没有报错,就说明 Service 可以被你直接启动(未做权限校验,危险)。
  • 如果系统返回 SecurityException,可能是代码中有手动权限校验。

📚 常见漏洞示例


✅ 1. 命令执行漏洞(RCE)

📜 Manifest 配置

 <service
     android:name=".ExecService"
     android:exported="true" />

🧨 示例代码

 public class ExecService extends Service {
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         String cmd = intent.getStringExtra("cmd");
         Runtime.getRuntime().exec(cmd); // ❌ 未校验直接执行任意命令
         return START_NOT_STICKY;
     }
 }

🧨 旧版本代码(IntentService):

 public class ExecIntentService extends IntentService {
     public ExecIntentService() {
         super("ExecIntentService");
     }
 ​
     @Override
     protected void onHandleIntent(Intent intent) {
         String cmd = intent.getStringExtra("cmd");
         Runtime.getRuntime().exec(cmd);  // 未校验直接执行
     }
 }

🔍 关键词

  • Runtime.getRuntime().exec
  • ProcessBuilder
  • getStringExtra("cmd")
  • android:exported="true"

⚠️ 风险说明

外部 App 可通过构造恶意 Intent 实现远程命令执行,例如:

 adb shell am startservice -n com.vuln/.ExecService --es cmd "rm -rf /sdcard"
 adb shell am startservice -n com.vuln/.ExecService --es cmd "id > /sdcard/test.txt"

🔎 排查流程

 AndroidManifest.xml
   └─ Service 配置是否导出
       └─ 检查 onStartCommand 或 onHandleIntent 方法
           └─ 是否从 Intent 获取参数
               └─ 是否传入敏感 API(如 exec)
                   └─ 是否缺少参数校验或权限控制

🛡️ 修复建议

  • 禁止导出:android:exported="false"
  • 添加权限或校验调用者包名
  • 限制命令在白名单范围内

✅ 2. 权限绕过漏洞

主要用于旧版APP检测,9以上基本不用检测这项

📜 Manifest 配置

 <service
     android:name=".DeleteAppService"
     android:exported="true" />

🧨 示例代码

 public class DeleteAppService extends Service {
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         String pkg = intent.getStringExtra("pkg");
         getPackageManager().deletePackage(pkg, null, 0); // ❌ 无权限判断
         return START_NOT_STICKY;
     }
 }

🧨 旧版本代码(IntentService):

 public class DeleteAppIntentService extends IntentService {
     public DeleteAppIntentService() {
         super("DeleteAppIntentService");
     }
 ​
     @Override
     protected void onHandleIntent(Intent intent) {
         String pkg = intent.getStringExtra("pkg");
         getPackageManager().deletePackage(pkg, null, 0);  // 无鉴权
     }
 }

🔍 关键词

  • deletePackage
  • PackageManager
  • getStringExtra("pkg")

⚠️ 风险说明

攻击者可调用该服务删除其他 App(前提:拥有系统权限或被赋权)。

 adb shell am startservice -n com.example.vuln/.DeleteAppService --es pkg "com.android.settings"

🔎 排查流程

 AndroidManifest.xml
   └─ 导出 Service 检查
       └─ onStartCommand 或 onHandleIntent 是否处理敏感功能
           └─ 是否传入 PackageManager 敏感操作
               └─ 是否校验调用方身份或权限

🛡️ 修复建议

  • 添加权限控制:android:permission
  • 使用 checkCallingPackage() 验证来源
  • 拒绝非系统调用或加签限制

✅ 3. 敏感信息泄露(Bind Service)

📜 Manifest 配置

 <service
     android:name=".TokenService"
     android:exported="true" />

🧨 示例代码:

 public class TokenService extends Service {
     private final IBinder binder = new MyBinder();
 ​
     public class MyBinder extends Binder {
         public String getToken() {
             return AppConfig.SESSION_TOKEN; // ❌ 敏感信息直接返回
         }
     }
 ​
     @Override
     public IBinder onBind(Intent intent) {
         return binder;
     }
 }

🔍 关键词

  • onBindBindergetToken()
  • SharedPreferences.getString / AppConfig.xxx

⚠️ 风险说明

外部 App 可绑定该 Service 并调用公开方法获取敏感信息。

利用示例与说明 👉 Android 绑定服务是怎么回事?一文带你看懂原理与信息泄露风险-极客星球

🔎 排查流程

 AndroidManifest.xml
   └─ 检查 exported="true"
       └─ 是否为 bind 类型服务
           └─ 返回 Binder 是否包含敏感方法
               └─ 是否未加权限限制

🛡️ 修复建议

  • 使用 android:permission 限制绑定
  • 敏感方法加权限或调用方校验
  • 或干脆不导出:android:exported="false"

✅ 4. SQL 注入漏洞

📜 Manifest 配置

 <service
     android:name=".QueryService"
     android:exported="true" />

🧨 示例代码

 public class QueryService extends Service {
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         String name = intent.getStringExtra("name");
         Cursor cursor = db.rawQuery("SELECT * FROM user WHERE name='" + name + "'", null); // ❌ 拼接 SQL
         return START_NOT_STICKY;
     }
 }

🧨 旧版本代码(IntentService):

 public class QueryIntentService extends IntentService {
     public QueryIntentService() {
         super("QueryIntentService");
     }
 ​
     @Override
     protected void onHandleIntent(Intent intent) {
         String name = intent.getStringExtra("name");
         db.rawQuery("SELECT * FROM user WHERE name='" + name + "'", null);  // 拼接注入
     }
 }

🔍 关键词

  • rawQuery("SELECTexecSQL("
  • + 参数 + 拼接
  • getStringExtra("name")

⚠️ 风险说明

攻击者可注入恶意 SQL:

 adb shell am startservice -n com.example.vuln/.QueryService --es name "' OR 1=1 --"

🔎 排查流程

 AndroidManifest.xml
   └─ 检查 Service 是否导出
       └─ onStartCommand 或 onHandleIntent 是否拼接 SQL
           └─ 是否直接使用外部输入构建语句

🛡️ 修复建议

  • 改为参数绑定方式: db.rawQuery(“SELECT * FROM user WHERE name=?”, new String[]{name});
  • 增加正则校验输入合法性

✅ 5. 拒绝服务漏洞(DoS)

📜 Manifest 配置

 <service
     android:name=".HeavyService"
     android:exported="true" />

🧨 示例代码

 public class HeavyService extends Service {
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         for (int i = 0; i < 10000000; i++) {
             Math.sqrt(i); // ❌ 无限制的重运算
         }
         return START_NOT_STICKY;
     }
 }

🧨 旧版本代码(IntentService):

 public class HeavyIntentService extends IntentService {
     public HeavyIntentService() {
         super("HeavyIntentService");
     }
 ​
     @Override
     protected void onHandleIntent(Intent intent) {
         for (int i = 0; i < 10000000; i++) {
             Math.sqrt(i);  // 高负载计算
         }
     }
 }

🔍 关键词

  • onStartCommand 中存在大循环
  • for (int i = 0; i < ...
  • startService 的频繁调用点

⚠️ 风险说明

攻击者频繁调用该服务,可能导致内存溢出 或系统卡顿。

 adb shell am startservice -n com.example.vuln/.HeavyService

🔎 排查流程

 AndroidManifest.xml
   └─ 查找 exported Service
       └─ onStartCommand 或 onHandleIntent 是否有大量计算/循环
           └─ 是否对调用频率进行限制

🛡️ 修复建议

  • 添加调用频率限制或冷却时间
  • 使用前台服务或 JobScheduler 控制运行条件
  • 添加权限限制或取消导出

✅ ADB 命令总结

1. 命令执行漏洞(RCE)

 adb shell am startservice -n com.example.vuln/.ExecService --es cmd "rm -rf /sdcard/"

📌 向导出服务传入恶意命令,触发 Runtime.getRuntime().exec(cmd) 执行任意命令。


2. 权限绕过攻击

 adb shell am startservice -n com.example.vuln/.DeleteAppService --es pkg "com.android.settings"

📌 利用无鉴权服务绕过权限检查,强行卸载任意包(如系统包需签名绕过)。


3. 敏感信息泄露(绑定服务)

❌ 无法直接用 ADB 利用,必须通过恶意 App 使用 bindService() 获取 Binder 后调用。


4. SQL 注入漏洞

 adb shell am startservice -n com.example.vuln/.QueryService --es name "' OR 1=1 --"

📌 向服务传递恶意 SQL 语句,拼接进 rawQuery() 导致注入漏洞。


5. 拒绝服务(DoS)

 adb shell am startservice -n com.example.vuln/.HeavyService

📌 重复调用该服务导致 CPU 计算密集,造成卡顿或系统崩溃。


📘 ADB 命令简要说明

 adb shell am startservice -n 包名/服务类名 --es 参数名 参数值

表示通过 ActivityManager (am) 工具发送一个启动服务的 Intent,并附带参数。


© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容