180421 安卓-DDCTF_WP(Android)

54 篇文章 1 订阅

要赶的WP太多了(:з」∠)日后有机会再把更详细的心得和内容补上吧

Android

RSA

垃圾代码比较多
动态调试,跟随输入值进入,发现将输入放在了一个结构体中,然后用后八字节作为指针来控制
要求len为31字节
将输入逐字节异或了一个数组以后,遍历结果,要求满足一下关系式:
a[i] == a[i+10]
即一个10字节长度的字符串循环3遍
通过校验以后将a[10]赋0,然后atoi转换为整型
用一个大数5889412424631952987去除这个整数,要求余数为0并且该整数小于商
进行大数分解后发现有两个因数:

1499419583<10> · 3927794789<10>

取较小的那个数,重复四遍后异或数组即可得到flag

a = [73, 90, 75, 10, 67, 92, 65, 80, 65, 75, 85, 93, 67, 13, 70, 64, 65, 1, 92, 6, 1, 89, 91, 14, 90, 82, 65, 93, 8, 94, 6]
r = "1499419583"*4
for i in range(31):
    print(chr(ord(r[i])^a[i]), end='')

Hello Baby Dex

jeb反编译后发现了大量第三方库,提取关键词robust搜索发现是热补丁技术
查找assets文件夹发现一个BMP,拖出来查看发现是zip结构,解压得到DEX文件,反编译之,在MainActivity$1Patch类中发现了Onclick函数的热补丁
与Invoke方法很类似,查找EnhancedRobustUtils.invokeReflectMethod的详细说明可以获知各个参数的意义
构造了一个String,然后将

DDCTF{ + Joseph(3,4) + Joseph(5, 6) + }
通过append方法连接起来,最后通过equals进行比较

刚开始用原DEX中的Joseph方法算了半天,翻过来覆过去python java试了个遍就是不对,最后才发现也被热补丁了,气爆

Joseph的热方法在MainActivityPatch类中,调用了一堆add方法,懒得搞了直接动态调试,在最后equals方法处拦截得到flag

Robust的各个方法介绍和原理在https://juejin.im/post/58e4ce652f301e006227ab40有比较详细的说明,包括xxPatch类,xxPatchControl类的作用等等

Diffie-Hellman

也是垃圾代码比较多,跟第一题如出一辙
动态调试找到几个核心关系

long long通过两个int型来保存,计算会麻烦一点,需要找到他们的真正关系

p 0xB4948 7B06AA40

mod_residual 0x1D026 744B3680

找到两个数p和mod_residual
程序中对2进行了左移的死循环,每左移一位进行一次模p的比较,要求余数为mod_residual
即满足下列关系式

2^n % 0xB49487B06AA40 == 0x1d026744b3680

爆破n,得到208603

ECC

反编译发现被混淆的非常非常严重,简单逆向可知是ECC算法的secp256k1曲线,通过输入的私钥来计算公钥,要求公钥的两个整数拼接起来为00AF576186553CC4B9224B738D89162F723BCFBF589CEF072A2C0ADA7B3443B5DC21D75144B89C87E3AC0BE030A1F5CE90E86F635D3E86271FB71375F5F581E9A2

为了爆破速度,找了一下午的C++的ECC实现,跑了一下发现计算出来的公钥不一样
用Python的ECC库加密得到的公钥数也不一样,无奈只好回头继续逆APP

多次动态调试无果,跟踪混淆过后的程序太痛苦了
代码导出到java中,也因为包名和类名的冲突而无法运行

纠结了许久乖乖静态分析,发现在org的某个库中有一些字符串,谷歌之终于找到该第三方库bouncycastle
一个一个类去比对,最后完全还原整个函数调用过程,一运行发现公钥得到的两个数还是不同,心态爆炸
突然发现IDE给了提示,这个函数被废弃了

于是找到getXCoord,结果终于相同
开始爆破,安心睡觉
第二天起来发现结果43458080

package me.company;
import java.math.BigInteger;
import java.security.spec.ECParameterSpec;
//import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;

import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.x9.X962NamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.asn1.sec.SECNamedCurves;
public class Main {

    public static void main(String[] args)
    {
        long n = 43450000;
        while (true) {
            if (c(n)) {
                break;
            }
            else{
                n++;
                if(n%10000==0)System.out.println(n);
            }
        }
        System.out.println("find it");
        System.out.println(n);
         // 43458080

    }

    public static boolean c(long i)
    {
        String m = "00AF576186553CC4B9224B738D89162F723BCFBF589CEF072A2C0ADA7B3443B5DC21D75144B89C87E3AC0BE030A1F5CE90E86F635D3E86271FB71375F5F581E9A2";
        //getParameterSpec("secp256k1").;
        String input = String.valueOf(i);
        BigInteger test = new BigInteger(input.getBytes());
        //BigInteger test = new BigInteger("1");
        //System.out.println(test);
        X9ECParameters ecP = SECNamedCurves.getByName("secp256k1");
        ECPoint g = ecP.getG();
        //System.out.println(g);
        ECPoint p = g .multiply(test);
        p.getX();
        BigInteger x = p.getXCoord().toBigInteger();
        BigInteger y = p.getYCoord().toBigInteger();
        //System.out.println(x);
        //System.out.println(y);
        byte[] v3 = x.toByteArray();
        byte[] v4 = y.toByteArray();
        byte[] v5 = new byte[v3.length + v4.length];
        int v0_3;
        for(v0_3 = 0; v0_3 < v5.length; ++v0_3) {
            byte v2_1 = v0_3 < v3.length ? v3[v0_3] : v4[v0_3 - v3.length];
            v5[v0_3] = v2_1;
        }

        StringBuilder v2_2 = new StringBuilder();
        int v3_1 = v5.length;
        for(v0_3 = 0; v0_3 < v3_1; ++v0_3) {
            v2_2.append(String.format("%02X", Byte.valueOf(v5[v0_3])));
        }
        return v2_2.toString().equals(m);
    }
}

破解密钥

反而比前面的几个题目都简单=。=
逆向发现so中对输入和一个数组进行了异或,结果要求和另一个数组相等
关键在于异或的那个数组是动态生成的,静态看了一下SHA256乱七八糟的调用了一大堆很麻烦,干脆动态调试得了
第一遍取到结果不对,回头看发现有取TraceID的地方
通过动态从Libc中取到的open和read函数取到TraceID,然后根据TraceID的字符串来取SHA256的值

调试的时候将read出来的值改为TraceID:\t0即可得到正确的数组,异或得flag

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值