In Blog

This is the third part of the story of the smart card track at NSEC 2013. You can see the first two parts: part 1 and part 2.

Now, I had found two flags and the next one was the Old encryption key used in the current applet. This gave me a good hint that I needed to look into the binary of the old applet provided on the page. I downloaded the file and got a .cap file which I instinctively opened in 7-zip (being used to jar files). It was indeed a zipped file, but it contained a bunch of other .cap files named Header.cap, Method.cap, Constant pool.cap, static fields.cap, etc. All these files were not zip files and contained only binary data. I could recognize the various components of a class file, but they were not in the usual format. I started looking around for a decompiling tool for Java Card applets.

After about an hour of trying various things and searching, I found a thread which mentioned that the Java Card SDK had a tool called Normalizer which would convert a .cap file into a .class file. I immediately downloaded the Java Card SDK, and ran the normalizer tool on the initial .cap file (the zipped one). The normalizer started running, but eventually crashed and gave an error about a ClassRef not found for Ref ###### (it was a high number that I don’t remember). At that point I was lost again. I used Vim in hex mode to open some .cap files, focusing on constant pool.cap as I expected important information to be in there, but found nothing (I tried submitting a lot of hex strings from these files as flags but got nowhere).

After looking at some problems in other tracks, I came back to this problem and decided to take the long way out: I decompiled the normalizer tool (written in java). Once I had this tool decompiled, I ran it in debug to find the error. It turns out that when initializing external reference, it adds all mentioned external references (other packages that your applet needs) but it doesn’t add the java.lang package (which is implicit). Therefore, as soon as a class from java.lang is referenced, it throws the exception. I changed the code a bit so that it included the java.lang package and the normalizer ran without errors and gave me an AAA.class file. This looks quick, but it took 30 to 45 minutes to finally get this .class file.

I immediately decompiled this class file into java code and saw that it encrypted CBC with an encryption key in a static field.

package io.nsec.javacard.OldCDCApplet;

import javacard.framework.*;
import javacard.security.AESKey;
import javacard.security.KeyBuilder;
import javacardx.crypto.Cipher;

public class AAA extends Applet
{

    private void method_token255_descoff88(APDU apdu)
    {
        byte abyte0[] = apdu.getBuffer();
        int i = (short)abyte0[4];
        int j = (short)(byte)apdu.setIncomingAndReceive();
        if((short)i != (short)j)
            ISOException.throwIt((short)26368);
        if(Util.arrayCompare(field_token0_descoff24, (short)0, abyte0, (short)5, (short)4) == 0)
        {
            field_token3_descoff45 = -1;
            return;
        }
        for(short word0 = (short)0; (short)word0 < 16; word0++)
        {
            field_token1_descoff31 = (AESKey)KeyBuilder.buildKey((byte)15, (short)128, false);
            field_token1_descoff31.setKey(sfield_token255_descoff17_staticref2, (short)0);
            field_token2_descoff38 = Cipher.getInstance((byte)13, false);
            field_token2_descoff38.init(field_token1_descoff31, (byte)2);
            field_token2_descoff38.doFinal(sfield_token255_descoff10_staticref0, (short)0, sfield_token255_descoff10_staticref0.length, abyte0, (short)0);
        }

        field_token3_descoff45 = (byte)(short)(field_token3_descoff45 - 1);
        Util.setShort(abyte0, (short)0, field_token3_descoff45);
        apdu.setOutgoingAndSend((short)0, (short)2);
        ISOException.throwIt((short)25344);
    }

    public void process(APDU apdu)
    {
        byte abyte0[] = apdu.getBuffer();
        if(abyte0[0] == 0)
        {
            if(abyte0[1] == -92)
            {
                Util.setShort(abyte0, (short)0, field_token3_descoff45);
                apdu.setOutgoingAndSend((short)0, (short)2);
                return;
            }
            if(abyte0[1] == 32 && abyte0[2] == 0 && abyte0[3] == 0 && abyte0[4] == 4)
                method_token255_descoff88(apdu);
            else
                ISOException.throwIt((short)27904);
        } else
        {
            ISOException.throwIt((short)27904);
        }
    }

    private AAA()
    {
        field_token3_descoff45 = -1;
    }

    public static void install(byte abyte0[], short word0, byte byte0)
    {
        (new AAA()).register();
    }

    private AESKey field_token1_descoff31;
    private Cipher field_token2_descoff38;
    byte field_token3_descoff45;
    static final byte sfield_token255_descoff10_staticref0[] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0
    };
    static final byte sfield_token255_descoff17_staticref2[] = {
        -15, -90, -15, -90, -15, -90, -15, -90, -15, -90,
        -15, -90, -15, -90, -15, -90
    };
    byte field_token0_descoff24[] = {
        48, 48, 48, 48
    };

}

I submitted this key and… Bingo! I had found the third flag.

Once again, after speaking with the organizers after the competition, they mentioned that if I had simply looked in the file named static fields.cap in a hex editor, I would have seen the key. It was true, I hadn’t looked in this file at all and the key did stand out because the rest of the file was pretty much all 0’s, but when you don’t know where to look, it is not easy guessing which piece of hex is the right key.

Anyway, I had my third flag and was fairly happy with the result so far.

Part 4 is next and will tell the amazing story of the fourth flag.

Leave a Comment

Start typing and press Enter to search