TPM Writeup

By
Sooraj V Nair
Published on
20 Sep 2020
10 min read
DOMECTF2020

Story

Umbrella Corporation has developed a new Trusted Platform Module for one of its unique weapons. Its backend code has been hacked by a hacker group and published on the dark web. Can you find what they are upto?

Solution

For this challenge, you are provided with a short Verilog program and a password protected zip file, which means the verilog file is the key to find the password for the zip file.

We need to understand how data is being saved in the chip, so let’s take a closer look at TPM.sv.

reg [6:0] mem [9:0]; reg [5:0] indx = 0; reg [69:0] array;

There are 10 memory registers named mem , each one 7 bits wide, a single idx register, 6 bits wide and initially set to 0 and an array name array which is 70 bit wide.

        wire [69:0] which = {mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7], mem[8], mem[9]};
        wire [69:0] signal = {which[69:0]};
        wire [34:0] A = {mem[0], mem[1], mem[2], mem[3], mem[4]};
        wire [69:35] B = {mem[5], mem[6], mem[7], mem[8], mem[9]};
    

Here which consists of 10 memory registers, 7 bit each, both which and signal are 70 bit arrays and are the same.

A consists of memory registers from 0 to 4 and B consists of memory registers from 5 to 9. Here which array is split into two arrays A and B which are 35 bit wide each. The first 7 bits of the data will be stored in mem[0] and next 7 bits of data will be stored in mem[1] and so on.

        assign array = {B, A};
        assign Secret = signal == 69'd306741091925721928186;

        always @(posedge clk) begin
        
        mem[indx] <= data;
        for (i = 0; i < 5; i = i + 1) begin
        mem[i] = mem[i] << 1;
        end
    

Now, the arrays are concatenated as BA (previously it was AB). Secret will be true if the output of the signal is equal to the decimal number 306741091925721928186, so we’ll need to figure this out.

At each positive cycle of the clock, the input data is saved to the indx index of memory and memory registers mem[0] to mem[5] ( A ), is left shifted by 1 bit.

So what this systemverilog code does is, here we have signal to be equal to decimal value 306741091925721928186 it is converted into binary which is

        0100001010000011100011010001011110110000101000000110001101000111111010
    

(a zero is added to have exactly 70 bits).

The first 7 bits of this signal correspond to mem[0] , next 7 bit to mem[1] and so on. The value in signal will be:

        signal : {mem[0],    mem[1],  mem[2],  mem[3],  mem[4],  mem[5],    mem[6],  mem[7],  mem[8],     mem[9]}
                0100001    0100000  1110001 1010001   0111101  1000010  1000000  1100011  0100011 1111010
    

Then the signal is split into A and B which is 35 bits each, mem[0] to mem[4] is stored in A and mem[5] to mem[9] in B. Now A and B will be:

        A = { mem[0],      mem[1], 	   mem[2], 	   mem[3],     mem[4] }
            0100001      0100000      1110001    1010001      0111101 

        B = { mem[5],      mem[6],     mem[7],     mem[8],     mem[9] }
            1000010       1000000     1100011     0100011     1111010
    

At every positive edge of clock cycle mem[0] to mem[5] which is A, is left shifted by one bit. Now A will be:

        A = { mem[0],      mem[1],     mem[2],      mem[3],      mem[4] }
            1000010      1000000     1100010      0100010      1111010
    

Then A and B are concatenated as BA and are stored in array.

        array= {mem[5],mem[6], mem[7],mem[8], mem[9], mem[0], mem[1],mem[2],mem[3],  mem[4]}
            1000010 1000000 1100011 0100011 1111010 1000010 1000000 1100010 0100010 1111010
    

This is how data is stored in the TPM chip. If we convert these 7 bit values to ASCII we get the password.

        array= {mem[5],mem[6], mem[7],mem[8], mem[9], mem[0], mem[1],mem[2],mem[3],  mem[4]}
            1000010 1000000 1100011 0100011 1111010 1000010 1000000 1100010 0100010 1111010
            B      @          c      #       z       B       @      b     "       z
    

Now we can open the zip file using this password B@c#zB@b”z to get the flag: domectf{pBxzcgTxDY11KYMZAYskFNapMQjiw9MJ}

Also you can write a testbench program to solve this. A sample testbench code would be like the following:

        module main;
            integer i;
        reg [6:0] mem [9:0]; // 10 element memory, 7 bits wide
        reg [5:0] indx = 0; // 6 bit wide
        reg [69:0] array ;
        wire [69:0] which = {mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7], mem[8], mem[9]};

        wire [69:0] signal = {which[69:0]};

        
        wire [34:0] A = {
            mem[0], mem[1],
            mem[2], mem[3], mem[4]
            };

        wire [69:35] B = {
            mem[5], mem[6],
            mem[7], mem[8], mem[9]
            };
        
        assign array = {B, A};
        assign Secret = signal == 69'd306741091925721928186;

        initial
                begin

                    mem[0] = 7'b0100001; // first 7 bits of the binary
                    mem[1] = 7'b0100000; // Second 7 bits of the memory
                    mem[2] = 7'b1110001; // Third 7 bits of the memory
                    mem[3] = 7'b1010001;
                    mem[4] = 7'b0111101;
                    mem[5] = 7'b1000010;
                    mem[6] = 7'b1000000;
                    mem[7] = 7'b1100011;
                    mem[8] = 7'b0100011;
                    mem[9] = 7'b1111010;
                #1 $display("original  = %069b", signal);

                for (i = 0; i < 5; i = i + 1) begin //for left shifting 1 bit
                    mem[i] = mem[i] << 1;
                end
                #1 $display("A   = %069b", A);
                #1 $display("B   = %069b", B);
                #1 $display("array   = %069b", array);

                
                #1 $write("Password  = "); // for converting binary to ASCII
                for (i = 5; i < 10; i = i + 1) begin
                    #1 $write("%c", mem[i]);
                end
                for (i = 0; i < 5; i = i + 1) begin
                    #1 $write("%c", mem[i]);
                    end
                    $finish ;
                end
        endmodule
    
Automated human-like penetration testing for your web apps & APIs
Teams using Beagle Security are set up in minutes, embrace release-based CI/CD security testing and save up to 65% with timely remediation of vulnerabilities. Sign up for a free account to see what it can do for you.

Written by
Sooraj V Nair
Sooraj V Nair
Cyber Security Engineer
Experience the Beagle Security platform
Unlock one full penetration test and all Advanced plan features free for 10 days
Find surface-level website security issues in under a minute
Free website security assessment
Experience the power of automated penetration testing & contextual reporting.