Hacker101 CTF Android challenges write up(一)
字数 1842 2025-08-22 12:23:00
Hacker101 CTF Android挑战解析与解题思路
1. H1 Thermostat挑战
1.1 应用概述
- 这是一个温度计应用,包含温度显示面板和调节功能
- 提示有两处flag需要发现
1.2 静态分析
-
Activity分析:
- 唯一Activity:ThermostatActivity
- 关键代码位于com.hacker101.level11包下
-
Flag发现:
- 搜索flag关键词发现两处关键代码:
// Flag 1 messageDigest.update("^FLAG^911074676b0d1ed58ba09ca5755930daf7266886bbcf32ca8f785f6e5c631eb9$FLAG$".getBytes()); // Flag 2 this.mHeaders.put("X-Flag", "^FLAG^ab34de7822af3f9f75b311e0dcca2d1db34b5e63aa4fbb7386696a547405405a$FLAG$");
- 搜索flag关键词发现两处关键代码:
-
网络请求分析:
- PayloadRequest类处理网络请求
- 请求URL:
https://d7299d*****4704859cc2cc8382.ctf.hacker101.com/ - 请求参数:
- "d":buildPayload(JSONObject)的结果
- "X-MAC":MD5("^FLAG^...\(FLAG\)" + buildPayload)的Base64编码
- "X-Flag":明文flag
1.3 动态分析
-
请求流程:
- setDefaults()方法初始化温度并发送请求
- 请求成功后回调更新温度值
-
抓包发现:
- 可以直接从X-Flag头获取第二个flag
- 第一个flag需要从代码中获取MD5前的原始值
1.4 解题步骤
- 直接查看代码中的两处flag定义
- 验证flag:
- 911074676b0d1ed58ba09ca5755930daf7266886bbcf32ca8f785f6e5c631eb9
- ab34de7822af3f9f75b311e0dcca2d1db34b5e63aa4fbb7386696a547405405a
2. Intentional Exercise挑战
2.1 应用概述
- 单一界面应用,包含一个"Flag"按钮
- 点击按钮显示"Invalid request"
2.2 静态分析
-
关键代码:
Uri data = getIntent().getData(); String str = "https://09f0e1735ea21fef3ae3c1578d677f09.ctf.hacker101.com/appRoot"; String str2 = BuildConfig.FLAVOR; if (data != null) { str2 = data.toString().substring(28); str = str + str2; } if (!str.contains("?")) { str = str + "?"; } MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update("s00p3rs3cr3tk3y".getBytes(StandardCharsets.UTF_8)); messageDigest.update(str2.getBytes(StandardCharsets.UTF_8)); webView.loadUrl(str + "&hash=" + String.format("%064x", new BigInteger(1, messageDigest.digest()))); -
哈希生成逻辑:
- 使用SHA-256算法
- 哈希输入:"s00p3rs3cr3tk3y" + str2
- str2为URL路径部分(去除前28个字符)
2.3 动态分析
-
正常流程:
- 点击Flag按钮请求URL:
ctf.hacker101.com/appRoot/flagBearer - 响应:"Invalid request"
- 点击Flag按钮请求URL:
-
抓包发现:
- 需要正确的hash参数才能获取flag
- hash = SHA256("s00p3rs3cr3tk3y/flagBearer")
2.4 解题方法
方法1:计算正确hash
- 计算字符串"s00p3rs3cr3tk3y/flagBearer"的SHA256哈希
- 将结果作为hash参数附加到URL
https://.../appRoot/flagBearer?&hash=<calculated_hash>
方法2:使用ADB命令
- 通过ADB命令直接启动带有正确路径的Activity:
adb shell am start -W -a "android.intent.action.VIEW" -d "http://level13.hacker101.com/flagBearer" com.hacker101.level13
3. Oauthbreaker挑战
3.1 应用概述
- 单一界面,包含"认证"按钮
- 点击后跳转浏览器进行OAuth认证
- 认证成功后返回应用显示"成功验证"
3.2 静态分析
MainActivity关键代码:
-
onCreate方法:
public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.activity_main); this.authRedirectUri = "oauth://final/"; try { Uri data = getIntent().getData(); if (data != null && data.getQueryParameter("redirect_uri") != null) { this.authRedirectUri = data.getQueryParameter("redirect_uri"); } } catch (Exception unused) { } this.button = (Button) findViewById(R.id.button); this.button.setOnClickListener(this); } -
onClick方法:
public void onClick(View view) { if (view.getId() != R.id.button) { return; } String str = null; try { str = "https://0b6**ded40f29af68fb3b108c.ctf.hacker101.com/oauth?redirect_url=" + URLEncoder.encode(this.authRedirectUri, StandardCharsets.UTF_8.toString()) + "login&response_type=token&scope=all"; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } Intent intent = new Intent("android.intent.action.VIEW"); intent.setData(Uri.parse(str)); startActivity(intent); }
BrowserActivity关键代码:
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_browser);
String str = "https://0b65afadf874ded40f29af68fb3b108c.ctf.hacker101.com/authed";
try {
Uri data = getIntent().getData();
if (data != null && data.getQueryParameter("uri") != null) {
str = data.getQueryParameter("uri");
}
} catch (Exception unused) {
}
WebView webView = (WebView) findViewById(R.id.webview);
webView.setWebViewClient(new SSLTolerentWebViewClient(webView));
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebAppInterface(getApplicationContext()), "iface");
webView.loadUrl(str);
}
WebAppInterface关键方法:
@JavascriptInterface
public String getFlagPath() {
String str = "";
try {
byte[] bArr = new byte[32];
new SecureRandom().nextBytes(bArr);
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(bArr);
str = Hex.encodeHexString(messageDigest.digest()) + ".html";
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return str;
}
3.3 解题步骤
Flag 1获取:
- 修改redirect_url参数为"oauth://final/login"
- 访问修改后的OAuth URL
- 从响应中获取token形式的flag
Flag 2获取:
- 利用WebView的JavaScript接口
- 调用getFlagPath()方法获取flag路径
- 计算得到路径:48ce217fea4529a070a9d3e3c87db512b1596d413e580f7b2e1eab65f3948ab8.html
- 拼接完整URL访问获取flag
4. 通用解题技巧总结
-
静态分析优先:
- 使用Jadx等工具反编译APK
- 搜索关键词如"flag"、"secret"等
- 重点关注网络请求相关代码
-
动态分析辅助:
- 使用抓包工具分析网络请求
- 监控Intent跳转和数据传递
- 观察WebView加载行为
-
常见漏洞点:
- 硬编码的凭证或flag
- 不安全的WebView配置(如启用JavaScript)
- 不完善的输入验证
- 不安全的Intent处理
-
ADB命令使用:
- 通过ADB命令触发特定Intent
- 测试不同URI和参数组合
-
加密哈希分析:
- 识别代码中的哈希算法(MD5、SHA等)
- 分析哈希输入构造方式
- 必要时重新实现哈希计算逻辑