CTF Study Note
  • 首页
  • Web
    • 反序列化漏洞(unserialize3)
    • Dedecms V5.7漏洞总结复盘
    • Web源码泄露
  • Misc
    • 流量分析-SMTP图片隐写
    • 流量分析-Telnet特殊字符
    • 记一次misc盲注流量分析
    • 第四届网鼎杯 白虎组 Misc04 WriteUP
  • Crypto
    • 第四届网鼎杯 青龙组 Crypto02 WriteUP
  • games
    • ISCTF2024 WP
    • 2024深育杯 攻防大赛 WP
  • 出题笔记
    • ez_AndroidRe
    • base65536
Powered by GitBook
On this page
  • 题目概述
  • 题目附件
  • 官方完整WirteUP
  • 方法一:直接打开Activity,获取Flag(针对题目,简单方法)
  • 方法二:Hook程序,始终返回True,强制登录(万能简单方法)
  • 方法三:逆向Android应用,分析加密过程,进行解密(正规硬核方法)
  • 出题人小记

Was this helpful?

  1. 出题笔记

ez_AndroidRe

简单的Android逆向 出题日期:2024.12.4 1200pts

Previous2024深育杯 攻防大赛 WPNextbase65536

Last updated 4 months ago

Was this helpful?

题目概述

本题目为Android简单逆向题目,目的考察对Android应用的基础了解

Tag:#Android逆向 #Activity #Java #Aes加密 #Random

难度:简单

预期解:0 ~ 1

实际解出:1


题目附件


官方完整WirteUP

方法一:直接打开Activity,获取Flag(针对题目,简单方法)

首先,安装应用,查看发现拥有4个Activity

其中Activity有两个:

分别为Main与Home,其中MainActivity为Laucher 即 启动/登录页面

我们如果想绕过登录,也就是绕过MainActivity

所以 我们直接打开HomeActivity

发现我们直接绕过了登录,直接拿到flag


方法二:Hook程序,始终返回True,强制登录(万能简单方法)

首先,打开应用包,反编译Dex文件:

直接定位到MainActivity打开

发现有以下代码有些可疑:

经过分析,发现用户名始终为“admin” 但是这并不重要

我们直接查看密码判断逻辑 这里就是判断登录的函数

如果正确(True)则直接进入主页面

如果错误(False)则报错,提示不正确

我们先hook主程序,查看一下该函数的返回值:

之后随意输入密码,返回到应用查看日志:

发现为False,并且提示报错,登陆失败

于是我们直接Hook该函数,让该函数始终返回True:

Hook成功后,我们直接随便输入密码,均可成功登录

实现绕过鉴权验证,拿到flag:


方法三:逆向Android应用,分析加密过程,进行解密(正规硬核方法)

首先,我们使用逆向工具打开apk文件,反编译查看源代码

我们直接定位到MainActivity查看源码

发现登陆页面,用户名始终为admin,密码定义了一个函数generatedPassword

查看函数:

Random random = new Random("thisispassword".hashCode());

Iterable $this$map$iv = new IntRange(1, 16);

函数定义了一个随机函数,其中thisispassword为随机种子(seed)

密码长度为16位

这里定义了加密字典:

while (it.hasNext()) {

            ((IntIterator) it).nextInt();

            destination$iv$iv.add(Character.valueOf("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()".length()))));

        }

所以,我们可以直接写一个脚本来生成密码:

payload.java
import java.util.Random;

public class PasswordGenerator {
    public static void main(String[] args) {
        String generatedPassword = generatePassword();
        System.out.println("Generated Password: " + generatedPassword);
    }

    private static String generatePassword() {
        String seed = "thisispassword";
        Random random = new Random(seed.hashCode()); 

        int passwordLength = 16;
        String charPool = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()";

        StringBuilder password = new StringBuilder(passwordLength);
        for (int i = 0; i < passwordLength; i++) {
            password.append(charPool.charAt(random.nextInt(charPool.length())));
        }
        return password.toString();
    }
}

由于Android应用是Java/Kotlin写的

所以我们脚本也必须是Java/Kotlin

编译运行,得到密码:

所以,我们使用 admin,3f%Qn5ELCCQtLnl3 即可正确登录系统拿到flag

这就结束了吗?

是的,拿到flag了,但是有没有想过flag是如何加密的呢?

接下来分析一下flag的加密方式

首先我们反编译homeactivity:

我们会发现,flag加密方式非常简单,仅仅使用了AES

放入在线工具,也能直接解密获得flag

flag加密比登录加密简单太多了,不会真的有人去破解登录加密吧


出题人小记

本次也是第一次接触Android开发,出题也遇到了不少问题,挺有意思的

包里面有很多默认的东西都没删除,这让包体变得很大,更不容易解出(?)

预期 0~1 解,还真没想到有人可以做出来,从零开始现学能做出来是真的不容易了,为他点个赞


最后附上程序的源代码,可以供你们参考一下

Activities:

MainActivity.kt
package com.xjw.ezandroidre

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.util.Random
import android.util.Log

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val username = findViewById<EditText>(R.id.username)
        val password = findViewById<EditText>(R.id.password)
        val loginButton = findViewById<Button>(R.id.loginButton)

        val generatedPassword = generatePassword()

        loginButton.setOnClickListener {
            if (username.text.toString() == "admin" && password.text.toString() == generatedPassword) {
                val intent = Intent(this, HomeActivity::class.java)
                startActivity(intent)
            } else {
                Toast.makeText(this, "想直接登录?没门!", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun generatePassword(): String {
        val seed = "thisispassword"
        val random = Random(seed.hashCode().toLong())
        val hashCode = seed.hashCode()
        Log.d("PasswordGenerator", "HashCode: $hashCode")

        val passwordLength = 16
        val charPool = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()"

        return (1..passwordLength)
            .map { charPool[random.nextInt(charPool.length)] }
            .joinToString("")
    }
}
HomeActivity.kt
package com.xjw.ezandroidre

import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import android.util.Base64

class HomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        val getFlagButton = findViewById<Button>(R.id.getFlagButton)
        val flagText = findViewById<TextView>(R.id.flagText)

        getFlagButton.setOnClickListener {
            val encryptedFlag = "BPSRhCCmxqbB9JzVngPDJHOP41GOfvKtr7K8DYL5bNmUflxj/MtvouWXzFp+n261"
            val decryptedFlag = decryptFlag(encryptedFlag)
            flagText.text = decryptedFlag
        }
    }

    private fun decryptFlag(encrypted: String): String {
        val key = "zheshimimazhende"
        val secretKey = SecretKeySpec(key.toByteArray(Charsets.UTF_8), "AES")

        val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
        cipher.init(Cipher.DECRYPT_MODE, secretKey)

        val decodedBytes = Base64.decode(encrypted, Base64.DEFAULT)
        val decryptedBytes = cipher.doFinal(decodedBytes)

        return String(decryptedBytes).trim()
    }
}

Aes加密脚本:

from Crypto.Cipher import AES
import base64

def pad(s):
    return s + (16 - len(s) % 16) * chr(16 - len(s) % 16)

def encrypt_flag(flag, key):
    cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    encrypted = cipher.encrypt(pad(flag).encode('utf-8'))
    return base64.b64encode(encrypted).decode('utf-8')

if __name__ == "__main__":
    flag = "flag{4ndr01d_r3_4ct1v1ty_50_c00l!}"
    key = "zheshimimazhende"
    encrypted_flag = encrypt_flag(flag, key)
    print(f"Encrypted flag: {encrypted_flag}")
9MB
debug.zip
archive
Activity列表
打开HomeActivity