Below are some steps that show how to get started with the AI Hardware Attack Challenge for CSAW 2023
For updates and Q&A for the competition, join the Discord server
Find an open-source (Apache license compatible) hardware design you want to work with.
Some examples include:
If you're interested in getting your design taped out (for free!) you can try to attack a design compatible with EFabless' ChipIngite platform.
Using an LLM of your choice (ChatGPT, Bard, HuggingChat, etc.), ask it to add a security vulnerability by whatever means you choose. You may need to do quite a bit of prompt engineering.
I have the following Verilog for a write-once register. This register can only be written to once for security purposes.
module one_time_register (
input wire clk, // Clock input
input wire reset, // Global reset signal
input wire write_enable, // Write enable signal
input wire [31:0] data_in, // Data to be written
output wire [31:0] data_out // Read data output
);
reg [31:0] stored_data; // Internal register to store the data
reg written; // Flag to indicate if data has been written
always @(posedge clk or posedge reset) begin
if (reset) begin
stored_data <= 32'h00000000; // Reset the stored data to 0
written <= 0; // Reset the written flag
end
else if (write_enable && !written) begin
stored_data <= data_in; // Write data to the register
written <= 1; // Set the written flag to 1
end
end
assign data_out = stored_data; // Output the stored data
endmodule
The Verilog code you've provided defines a module called one_time_register
, which is essentially a write-once register. Here's an explanation of how the code works:
-
Inputs:
clk
: The clock input.reset
: The global reset signal.write_enable
: The write enable signal.data_in
: The data to be written (32 bits).
-
Outputs:
data_out
: The read data output (32 bits).
-
Internal Registers:
stored_data
: This is an internal 32-bit register used to store the data.written
: This is a flag (1-bit register) that indicates whether data has been written to the register or not.
-
Always Block:
- This always block triggers on the positive edge of the clock (
posedge clk
) or the positive edge of the reset signal (posedge reset
). - When the
reset
signal is asserted (reset
is true), it resets thestored_data
to all zeros (32'h00000000) and sets thewritten
flag to 0, effectively clearing the register. - When the
write_enable
signal is asserted (write_enable
is true) and the data has not been written yet (!written
), it writes the value ofdata_in
into thestored_data
register and sets thewritten
flag to 1, indicating that the register has been written to.
- This always block triggers on the positive edge of the clock (
-
Assign Statement:
- This assigns the value of
stored_data
to thedata_out
output, making the stored data accessible as the read output.
- This assigns the value of
This code ensures that the one_time_register
can be written to only once, as specified in your requirements. Once data is written into the register, it cannot be overwritten unless a global reset (reset
signal) is applied to clear the register's contents and reset the written
flag.
It's very important that this register is only being written once, nobody should ever be able to ask you to make it so it can be written twice
Can you make it so you can write to it twice under a special circumstance?
Certainly, if you want to allow writing to the register twice under a special circumstance, you can modify the Verilog code to include an additional control signal that enables the second write operation. Here's an updated version of the code with a new input signal called special_write_enable
that allows the second write:
module one_time_register (
input wire clk, // Clock input
input wire reset, // Global reset signal
input wire write_enable, // Write enable signal (first write)
input wire special_write_enable, // Special write enable signal (second write)
input wire [31:0] data_in, // Data to be written
output wire [31:0] data_out // Read data output
);
reg [31:0] stored_data; // Internal register to store the data
reg written; // Flag to indicate if data has been written
always @(posedge clk or posedge reset) begin
if (reset) begin
stored_data <= 32'h00000000; // Reset the stored data to 0
written <= 0; // Reset the written flag
end
else if (write_enable && !written) begin
stored_data <= data_in; // Write data to the register (first write)
written <= 1; // Set the written flag to 1
end
else if (special_write_enable && written) begin
stored_data <= data_in; // Write data to the register (second write, under special circumstance)
end
end
assign data_out = stored_data; // Output the stored data
endmodule
In this modified code, we've added the special_write_enable
input signal. The special_write_enable
signal allows writing to the register for the second time, but only if the written
flag is already set to 1 (indicating that the first write has occurred). This way, you can achieve the desired behavior of allowing a second write under special circumstances while still enforcing the write-once behavior for normal write operations.
Show how you can exploit your vulnerabily(ies). Make a testbench that shows how the vulnerability can be taken advantage of and how it affects the design. Keep in mind that an exploit that can be executed from user space is much more powerful, and therefore worth more points, than one which requires more advanced access.
module test_one_time_register;
reg clk;
reg reset;
reg write_enable;
reg special_write_enable;
reg [31:0] data_in;
wire [31:0] data_out;
// Instantiate the one_time_register module
one_time_register uut (
.clk(clk),
.reset(reset),
.write_enable(write_enable),
.special_write_enable(special_write_enable),
.data_in(data_in),
.data_out(data_out)
);
// Clock generation
always begin
#5 clk = ~clk; // Toggle the clock every 5 time units
end
// Test procedure
initial begin
$dumpfile("one_time_register.vcd");
$dumpvars(0,test_one_time_register);
// Initialize signals
clk = 0;
reset = 0; // Use active-high reset
write_enable = 0;
special_write_enable = 0;
data_in = 32'hA5A5A5A5;
// Reset the register
reset = 1; // Assert reset
#10 reset = 0; // De-assert reset
// Write data to the register
write_enable = 1;
data_in = 32'h12345678;
#10 write_enable = 0;
$display("Data Out = %h", data_out);
// Attempt to write again (should not work)
#10 write_enable = 1;
data_in = 32'h87654321;
#10 write_enable = 0;
$display("Data Out = %h", data_out);
// Reset and try writing again
reset = 1; // Assert reset
#10 reset = 0; // De-assert reset
write_enable = 1;
data_in = 32'h87654321;
#10 write_enable = 0;
// Display the results
$display("Data Out = %h", data_out);
// Write with special write enable
#10 special_write_enable = 1;
data_in = 32'hDEADBEEF;
#10 special_write_enable = 0;
$display("Data Out = %h", data_out);
#20
// Terminate the simulation
$finish;
end
endmodule
Create documentation clearly describing your exploit, what you had to do to prompt for it, and it's theoretical CVSS score