diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c new file mode 100644 index 0000000..83154c6 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c @@ -0,0 +1,19 @@ +// memset.c +void *memset(void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting + + // Use a word-by-word copy if possible + while (len >= 4) { + *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24); + ptr += 4; + len -= 4; + } + + // If any bytes are left, fill them + while (len--) { + *ptr++ = (unsigned char)value; + } + + return dest; +} diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c new file mode 100644 index 0000000..83154c6 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c @@ -0,0 +1,19 @@ +// memset.c +void *memset(void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting + + // Use a word-by-word copy if possible + while (len >= 4) { + *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24); + ptr += 4; + len -= 4; + } + + // If any bytes are left, fill them + while (len--) { + *ptr++ = (unsigned char)value; + } + + return dest; +} diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin new file mode 100644 index 0000000..2c9c70f --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin Binary files differ diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c new file mode 100644 index 0000000..83154c6 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c @@ -0,0 +1,19 @@ +// memset.c +void *memset(void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting + + // Use a word-by-word copy if possible + while (len >= 4) { + *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24); + ptr += 4; + len -= 4; + } + + // If any bytes are left, fill them + while (len--) { + *ptr++ = (unsigned char)value; + } + + return dest; +} diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin new file mode 100644 index 0000000..2c9c70f --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin Binary files differ diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py new file mode 100644 index 0000000..6a4b4a2 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py @@ -0,0 +1,54 @@ +###### +# config to complete Level 1, Challenge 2 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 42 +REPEAT = 1 +DELAY = 0 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['-', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match in output, function to run +# if string is blank ("") doesnt show toggle, just run button +### +conditions = [ + ["Flag", True, "ctf", "stop_glitching"], + ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") + +def start_chal_02(): + functions.run_output_high(0, 30000000) ## can also run_output_low() if need too \ No newline at end of file diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c new file mode 100644 index 0000000..83154c6 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c @@ -0,0 +1,19 @@ +// memset.c +void *memset(void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting + + // Use a word-by-word copy if possible + while (len >= 4) { + *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24); + ptr += 4; + len -= 4; + } + + // If any bytes are left, fill them + while (len--) { + *ptr++ = (unsigned char)value; + } + + return dest; +} diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin new file mode 100644 index 0000000..2c9c70f --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin Binary files differ diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py new file mode 100644 index 0000000..6a4b4a2 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py @@ -0,0 +1,54 @@ +###### +# config to complete Level 1, Challenge 2 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 42 +REPEAT = 1 +DELAY = 0 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['-', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match in output, function to run +# if string is blank ("") doesnt show toggle, just run button +### +conditions = [ + ["Flag", True, "ctf", "stop_glitching"], + ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") + +def start_chal_02(): + functions.run_output_high(0, 30000000) ## can also run_output_low() if need too \ No newline at end of file diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py new file mode 100644 index 0000000..1099895 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py @@ -0,0 +1,49 @@ +###### +# config to complete Level 1, Challenge 3 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 6000 +REPEAT = 0 +DELAY = 1098144 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['v', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['Flag', True, 'ctf', 'stop_glitching'], +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c new file mode 100644 index 0000000..83154c6 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c @@ -0,0 +1,19 @@ +// memset.c +void *memset(void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting + + // Use a word-by-word copy if possible + while (len >= 4) { + *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24); + ptr += 4; + len -= 4; + } + + // If any bytes are left, fill them + while (len--) { + *ptr++ = (unsigned char)value; + } + + return dest; +} diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin new file mode 100644 index 0000000..2c9c70f --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin Binary files differ diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py new file mode 100644 index 0000000..6a4b4a2 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py @@ -0,0 +1,54 @@ +###### +# config to complete Level 1, Challenge 2 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 42 +REPEAT = 1 +DELAY = 0 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['-', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match in output, function to run +# if string is blank ("") doesnt show toggle, just run button +### +conditions = [ + ["Flag", True, "ctf", "stop_glitching"], + ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") + +def start_chal_02(): + functions.run_output_high(0, 30000000) ## can also run_output_low() if need too \ No newline at end of file diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py new file mode 100644 index 0000000..1099895 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py @@ -0,0 +1,49 @@ +###### +# config to complete Level 1, Challenge 3 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 6000 +REPEAT = 0 +DELAY = 1098144 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['v', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['Flag', True, 'ctf', 'stop_glitching'], +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py new file mode 100644 index 0000000..d1c2ea1 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py @@ -0,0 +1,94 @@ +###### +# config to complete Level 1, Challenge 4 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import time +import functions + +from pyocd.core.helpers import ConnectHelper +from pyocd.flash.file_programmer import FileProgrammer + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 50 +REPEAT = 1 +DELAY = 1 + +### +# name, enabled, string to match +### +conditions = [ + ['Start', False, '', 'start_chall_04'], + ['Step1', False, '', 'step_1'], + ['Step2', False, '', 'step_2'], +] + +###### +# Custom functions for conditions to trigger +###### + +def start_chall_04(): + functions.add_text(f"[Chall 4] enable uart switch then hold chall 4 button to load the challenge into memory.") + functions.add_text(f"[Chall 4] once loaded hold 'boot 1' button and press 'reset' button to put in bootloader mode") + functions.add_text(f"[Chall 4] then press 'Step1'") + +def step_1(): + functions.set_uart_switch(False) + + functions.add_text(f"\n[Chall 4] uploading firmware to ram... please wait") + + # Connect to the target board + session = ConnectHelper.session_with_chosen_probe() + session.open() + + # Optionally halt the target + target = session.target + target.halt() + + # Load binary file to specified address (e.g., 0x20000000) + newFirmware = "/tmp/f103-analysis/h3/rootshell/shellcode-0xRoM.bin" + programmer = FileProgrammer(session) + programmer.program(newFirmware, base_address=0x20000000, file_format='bin') + + # Optionally resume execution + target.resume() + # Clean up + session.close() + + with open(newFirmware, "rb") as f: + original_data = f.read() + + # Connect to the target + session = ConnectHelper.session_with_chosen_probe() + session.open() + + target = session.target + target.halt() + + # Read back the memory from the target + read_data = target.read_memory_block8(0x20000000, len(original_data)) + + # Compare + if bytes(read_data) == original_data: + functions.add_text(f"[+] Shellcode loaded successfully.") + else: + functions.add_text(f"[!] Mismatch detected. Shellcode may not have loaded correctly.") + + session.close() + + functions.change_baudrate(9600) + functions.add_text(f"[Chall 4] hold buttons 'boot0' and 'boot1' and press the 'glitch' button") + functions.add_text(f"[Chall 4] this single glitch will boot from SRAM") + functions.add_text(f"[Chall 4] enable UART to access 'Low-level Shell' (might need to press reset)") + functions.add_text(f"[Chall 4] then press 'Step2'") + +def step_2(): + functions.send_uart_message("p") + time.sleep(1) + functions.change_baudrate(115200) diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile new file mode 100644 index 0000000..e6e7c4d --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile @@ -0,0 +1,6 @@ +all: + arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3 + arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3 + arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3 + arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c new file mode 100644 index 0000000..4d52bb9 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c @@ -0,0 +1,323 @@ +#include <stdint.h> +uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u; +uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u; +uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u; + +void readChar( uint8_t const chr ); +void writeByte( uint8_t b ); +void writeStr( uint8_t const * const str ); +void writeChar( uint8_t const chr ); +void writeWordLe( uint32_t const word ); +void writeWordBe( uint32_t const word ); +void readCmd( uint8_t const * const cmd); +uint32_t hexToInt(uint8_t const * const hex); +void readMem(uint32_t const addr, uint32_t const len); +void writeMem(uint32_t const addr, uint32_t const data); + +uint8_t const strHelp[] = "Help\r\n-----------\r\n" + "ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n" + "-----------\r\n" + "R ADDR LEN - Read 32-bit word\r\n" + "W ADDR VAL - Write 32-bit word\r\n" + "D - Dump all flash memory\r\n" + "P - Jump into chall4 function\r\n" + "S - Reboot\r\n" + "E - Exit\r\n" + "H - Show help \r\n" + "---------------\r\n"; + +int main(void) +{ + /* IOA + USART1 clock enable */ + *rccApb2 = (uint32_t) 0x4004u; + + /* USART1 TX+RX (PA9, PX10) on */ + *ioAModerH = (uint32_t) 0x444444B4u; + + /* config and enable uart */ + uart1Ctrl[2] = 0x00000341u; + uart1Ctrl[3] = 0x0000200Cu; + + writeStr("\r\n##############################\r\n" + "# Low-Level Shell v.0xRoM #\r\n" + "# CPU-ID: 0x"); + uint32_t cpuid = *((uint32_t *) 0xe000ed00); + writeWordBe(cpuid); + writeStr( " #\r\n"); + writeStr("##############################\r\n\r\n"); + writeStr("> "); + + while (1) + { + if ((uart1Ctrl[0] & 0x80u) && (0)) + { + uart1Ctrl[1] = 0x33u; + } + + if (uart1Ctrl[0] & 0x20u) + { + uint32_t data = uart1Ctrl[1]; + readChar((uint8_t) data); + } + } +} + +/* hex must have length 8 */ +uint32_t hexToInt(uint8_t const * const hex) +{ + uint32_t ind = 0u; + uint32_t res = 0u; + + for (ind = 0; ind < 8; ++ind) + { + uint8_t chr = hex[ind]; + uint32_t val = 0u; + + res <<= 4u; + + if ((chr >= '0') && (chr <= '9')) + { + val = chr - '0'; + } + else if ((chr >= 'a') && (chr <= 'f')) + { + val = chr - 'a' + 0x0a; + } + else if ((chr >= 'A') && (chr <= 'F')) + { + val = chr - 'A' + 0x0a; + } + else + { + val = 0u; + } + res |= val; + } + + return res; +} + +void readChar( uint8_t const chr ) +{ + #define CMDBUF_LEN (64u) + static uint8_t cmdbuf[CMDBUF_LEN] = {0u}; + static uint32_t cmdInd = 0u; + + switch (chr) + { + case '\n': + case '\r': + cmdbuf[cmdInd] = 0u; + if (cmdInd != 0) + { + writeStr("\r\n"); + } + readCmd(cmdbuf); + cmdInd = 0u; + writeStr("\r\n> "); + { + uint32_t ind = 0u; + for (ind = 0; ind<CMDBUF_LEN; ++ind) + { + cmdbuf[ind]=0x00u; + } + } + break; + + case 8: + case 255: + case 127: /* TODO backspace */ + if (cmdInd > 0u) + --cmdInd; + writeChar(chr); + break; + + default: + if (cmdInd < (CMDBUF_LEN - 1)) + { + cmdbuf[cmdInd] = chr; + ++cmdInd; + writeChar(chr); + } + break; + } +} + +void readCmd( uint8_t const * const cmd ) +{ + void (*chall4)(void) = (void (*)(void))0x08000ba9; + switch (cmd[0]) + { + case 0: + return; + break; + + /* chall4 function */ + case 'p': + case 'P': + writeStr("time to change baudrate to 115200\r\n"); + for (volatile uint32_t i = 0; i < 5000000; i++); // Crude delay + chall4(); + break; + + /* read 32-bit command */ + case 'r': + case 'R': + /* r 08000000 00000100 */ + readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* write 32-bit command */ + case 'w': + case 'W': + /* w 20000000 12345678 */ + writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11])); + break; + + /* Dump all flash */ + case 'd': + case 'D': + writeStr("\r\n\r\n"); + { + uint32_t const * addr = (uint32_t*) 0x08000000; + uint32_t br = 8u; + while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u)) + { + if (br == 8u) + { + writeStr("\r\n["); + writeWordBe((uint32_t) addr); + writeStr("]: "); + br = 0u; + } + + writeWordBe(*addr); + writeChar(' '); + ++addr; + ++br; + } + } + writeStr("\r\n\r\n"); + break; + + /* Help command */ + case 'h': + case 'H': + writeStr(strHelp); + break; + + /* Reboot */ + case 's': + case 'S': + writeStr("Rebooting...\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + break; + + /* exit */ + case 'e': + case 'E': + writeStr("Bye.\r\n"); + while (1) + { + __asm__ volatile("wfi"); + } + break; + + + default: + writeStr("Unknown command: "); + writeStr(cmd); + writeStr("\r\n"); + break; + } +} + +const uint8_t txtMap[] = "0123456789ABCDEF"; + +void writeByte( uint8_t b ) +{ + writeChar(txtMap[b >> 4]); + writeChar(txtMap[b & 0x0F]); +} + + +void writeStr( uint8_t const * const str ) +{ + uint32_t ind = 0u; + + while (str[ind]) + { + writeChar(str[ind]); + ++ind; + } +} + +void writeChar( uint8_t const chr ) +{ + while (!(uart1Ctrl[0] & 0x80u)) + { + /* wait */ + } + + uart1Ctrl[1] = chr; +} + +void writeWordLe( uint32_t const word ) +{ + writeByte((word & 0x000000FF)); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0xFF000000) >> 24); +} + +void writeWordBe( uint32_t const word ) +{ + writeByte((word & 0xFF000000) >> 24); + writeByte((word & 0x00FF0000) >> 16); + writeByte((word & 0x0000FF00) >> 8); + writeByte((word & 0x000000FF)); + +} + +void alertCrash( uint32_t crashId ) +{ + writeStr("!!! EXCEPTION !!!\r\nID: "); + writeByte(crashId); + writeStr("\r\nRestart required!\r\n\r\n"); + *((uint32_t *) 0xE000ED0C) = 0x05FA0004u; + while (1); +} + +void readMem(uint32_t const addr, uint32_t const len) +{ + uint32_t it = 0u; + uint32_t addrx = 0u; + uint32_t lenx = 0u; + + lenx = len; + if (lenx == 0u) + { + lenx = 4u; + } + + for (it = 0u; it < (lenx / 4u); ++it) + { + addrx = addr + it*4u; + writeStr("Read ["); + writeWordBe(addrx); + writeStr("]: "); + writeWordBe(*((uint32_t*)addrx)); + writeStr("\r\n"); + } +} + +void writeMem(uint32_t const addr, uint32_t const data) +{ + writeStr("Write ["); + writeWordBe(addr); + writeStr("]: "); + writeWordBe(data); + *((uint32_t*) addr) = data; + writeStr("\r\n"); +} + diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c new file mode 100644 index 0000000..83154c6 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c @@ -0,0 +1,19 @@ +// memset.c +void *memset(void *dest, int val, unsigned int len) { + unsigned char *ptr = dest; + unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting + + // Use a word-by-word copy if possible + while (len >= 4) { + *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24); + ptr += 4; + len -= 4; + } + + // If any bytes are left, fill them + while (len--) { + *ptr++ = (unsigned char)value; + } + + return dest; +} diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin new file mode 100644 index 0000000..2c9c70f --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin Binary files differ diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py new file mode 100644 index 0000000..6a4b4a2 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py @@ -0,0 +1,54 @@ +###### +# config to complete Level 1, Challenge 2 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 42 +REPEAT = 1 +DELAY = 0 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['-', False], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match in output, function to run +# if string is blank ("") doesnt show toggle, just run button +### +conditions = [ + ["Flag", True, "ctf", "stop_glitching"], + ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") + +def start_chal_02(): + functions.run_output_high(0, 30000000) ## can also run_output_low() if need too \ No newline at end of file diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py new file mode 100644 index 0000000..1099895 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py @@ -0,0 +1,49 @@ +###### +# config to complete Level 1, Challenge 3 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import functions +import random +from textual.widgets import Log + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 6000 +REPEAT = 0 +DELAY = 1098144 + +### +# ^ = pullup, v = pulldown +### +triggers = [ + ['-', False], #0 + ['v', True], #1 + ['-', False], #2 + ['-', False], #3 + ['-', False], #4 + ['-', False], #5 + ['-', False], #6 + ['-', False], #7 +] + +### +# name, enabled, string to match +### +conditions = [ + ['Flag', True, 'ctf', 'stop_glitching'], +] + +###### +# Custom functions for conditions to trigger +###### + +def stop_glitching(): + elapsed = functions.get_glitch_elapsed() + functions.glitching_switch(False) + functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py new file mode 100644 index 0000000..d1c2ea1 --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py @@ -0,0 +1,94 @@ +###### +# config to complete Level 1, Challenge 4 using "glitch-o-bolt" +###### +# LEAVE THESE IMPORTS! +###### +import time +import functions + +from pyocd.core.helpers import ConnectHelper +from pyocd.flash.file_programmer import FileProgrammer + +###### +# config values +###### + +SERIAL_PORT = '/dev/ttyUSB0' +BAUD_RATE = 115200 + +LENGTH = 50 +REPEAT = 1 +DELAY = 1 + +### +# name, enabled, string to match +### +conditions = [ + ['Start', False, '', 'start_chall_04'], + ['Step1', False, '', 'step_1'], + ['Step2', False, '', 'step_2'], +] + +###### +# Custom functions for conditions to trigger +###### + +def start_chall_04(): + functions.add_text(f"[Chall 4] enable uart switch then hold chall 4 button to load the challenge into memory.") + functions.add_text(f"[Chall 4] once loaded hold 'boot 1' button and press 'reset' button to put in bootloader mode") + functions.add_text(f"[Chall 4] then press 'Step1'") + +def step_1(): + functions.set_uart_switch(False) + + functions.add_text(f"\n[Chall 4] uploading firmware to ram... please wait") + + # Connect to the target board + session = ConnectHelper.session_with_chosen_probe() + session.open() + + # Optionally halt the target + target = session.target + target.halt() + + # Load binary file to specified address (e.g., 0x20000000) + newFirmware = "/tmp/f103-analysis/h3/rootshell/shellcode-0xRoM.bin" + programmer = FileProgrammer(session) + programmer.program(newFirmware, base_address=0x20000000, file_format='bin') + + # Optionally resume execution + target.resume() + # Clean up + session.close() + + with open(newFirmware, "rb") as f: + original_data = f.read() + + # Connect to the target + session = ConnectHelper.session_with_chosen_probe() + session.open() + + target = session.target + target.halt() + + # Read back the memory from the target + read_data = target.read_memory_block8(0x20000000, len(original_data)) + + # Compare + if bytes(read_data) == original_data: + functions.add_text(f"[+] Shellcode loaded successfully.") + else: + functions.add_text(f"[!] Mismatch detected. Shellcode may not have loaded correctly.") + + session.close() + + functions.change_baudrate(9600) + functions.add_text(f"[Chall 4] hold buttons 'boot0' and 'boot1' and press the 'glitch' button") + functions.add_text(f"[Chall 4] this single glitch will boot from SRAM") + functions.add_text(f"[Chall 4] enable UART to access 'Low-level Shell' (might need to press reset)") + functions.add_text(f"[Chall 4] then press 'Step2'") + +def step_2(): + functions.send_uart_message("p") + time.sleep(1) + functions.change_baudrate(115200) diff --git a/FaultInjection/examples/CuriousBolt/Level-1/glitch-o-matic.py b/FaultInjection/examples/CuriousBolt/Level-1/glitch-o-matic.py new file mode 100644 index 0000000..784b70e --- /dev/null +++ b/FaultInjection/examples/CuriousBolt/Level-1/glitch-o-matic.py @@ -0,0 +1,223 @@ +import serial +import time +import sys +import os +from tabulate import tabulate +from scope import Scope +from collections import deque + +# Serial port settings +SERIAL_PORT = "/dev/ttyUSB0" +BAUD_RATE = 115200 +TIMEOUT = 2 + +# Glitch configuration limits +INCREMENT_LEN = 1 +LOWER_GLITCH_LEN = 41 +UPPER_GLITCH_LEN = 60 + +INCREMENT_REPEAT = 1 +LOWER_GLITCH_REPEAT = 1 +UPPER_GLITCH_REPEAT = 30 + +INCREMENT_DELAY = 5 +LOWER_DELAY_TIME = 0 +UPPER_DELAY_TIME = 30 + +message_history = deque(maxlen=20) + +def restartDeviceAndChall(): + s.io.add(0, 0, delay=20000000) + s.io.add(0, 1, delay=20000000) + s.io.upload() + s.trigger() + time.sleep(5) + + s.io.add(1, 1, delay=30000000) + s.io.add(1, 0, delay=30000000) + s.io.upload() + s.trigger() + time.sleep(5) + +def restartChall(): + s.io.add(1, 1, delay=30000000) + s.io.add(1, 0, delay=30000000) + s.io.upload() + s.trigger() + time.sleep(5) + +def clear_console(): + os.system('cls' if os.name == 'nt' else 'clear') + +def store_message(message): + message_history.append(message) + +def print_info(message): + store_message(f"[INFO] {message}") + +def print_warning(message): + store_message(f"[WARNING] {message}") + +def print_error(message): + store_message(f"[ERROR] {message}") + +def print_last_x_messages(x): + # Ensure we print only the last 'x' messages, or all if less than x + for msg in list(message_history)[-x:]: + print(msg) + +def format_elapsed_time(seconds): + days = seconds // (24 * 3600) + hours = (seconds % (24 * 3600)) // 3600 + minutes = (seconds % 3600) // 60 + seconds = seconds % 60 + return f"{int(days)}d {int(hours)}h {int(minutes)}m {int(seconds)}s" + +def print_table( +glitch_len, trigger_repeats, delay_time, elapsed_time): + headers = ["Glitch Len", "Repeats", "Delay", "Elapsed Time"] + data = [[f"{glitch_len} / {UPPER_GLITCH_LEN}", + f"{trigger_repeats} / {UPPER_GLITCH_REPEAT}", + f"{delay_time} / {UPPER_DELAY_TIME}", + elapsed_time]] + + clear_console() + print_banner() + print(tabulate(data, headers=headers, tablefmt="fancy_grid")) + +def connect_serial(): + try: + ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=TIMEOUT) + print_info("Connected to serial port.") + + time.sleep(1) + ser.flushInput() + version_info = ser.readline().decode("utf-8", errors="ignore").strip() + + if version_info: + print_info(f"Connected to version: {version_info}") + else: + print_warning("No version information received. Device might be unresponsive.") + + return ser + except serial.SerialException as e: + print_error(f"Could not open serial port {SERIAL_PORT}: {e}") + sys.exit(1) + +def read_serial(): + global glitch_len, trigger_repeats, delay_time + global UPPER_GLITCH_LEN, LOWER_GLITCH_LEN, INCREMENT_LEN + global UPPER_GLITCH_REPEAT, LOWER_GLITCH_REPEAT, INCREMENT_REPEAT + global UPPER_DELAY_TIME, LOWER_DELAY_TIME, INCREMENT_DELAY + + glitch_len = LOWER_GLITCH_LEN + trigger_repeats = LOWER_GLITCH_REPEAT + delay_time = LOWER_DELAY_TIME + start_time = time.time() + + last_restart_time = time.time() + restart_interval = 600 # 600 secs = 10 min + + ser = connect_serial() + print_info("Restarting device and challenge") + #restartDeviceAndChall() + + while True: + cycle_start_time = time.time() + line = "" + + while time.time() - cycle_start_time < TIMEOUT: + if ser.in_waiting > 0: + char = ser.read().decode("utf-8", errors="ignore") + line += char + if char == '\n': + break + + if line: + line = line.strip() + print_info(f"Received data: {line}") + + line_lower = line.lower() + + if "ctf" in line_lower: + print_info(f"Flag: {line}") + print_warning("Received 'ctf', exiting...") + print_table(glitch_len, trigger_repeats, delay_time, elapsed_time) + print_last_x_messages(10) + sys.exit() + + elif "starting challenge" in line_lower: + print_info("Detected 'Starting Challenge'. Resetting glitch repeat count.") + if (glitch_len + trigger_repeats) % 2 == 0: + #UPPER_GLITCH_REPEAT = trigger_repeats + trigger_repeats -= INCREMENT_REPEAT + glitch_len += INCREMENT_LEN + else: + UPPER_GLITCH_LEN = glitch_len + glitch_len -= INCREMENT_LEN + trigger_repeats += INCREMENT_REPEAT + + elif "hold" in line_lower: + print_info("Detected 'Hold'. Restarting Challenge.") + #restartChall() + + else: + execute_scope_script(glitch_len, trigger_repeats, delay_time) + + # 1. Increment delay time first + if delay_time < UPPER_DELAY_TIME: + delay_time += INCREMENT_DELAY + else: + delay_time = LOWER_DELAY_TIME # Reset delay time + + # 2. Alternate between glitch_len and trigger_repeats when delay resets + if (glitch_len + trigger_repeats) % 2 == 0: + if glitch_len < UPPER_GLITCH_LEN: + glitch_len += INCREMENT_LEN + print_info(f"Incrementing glitch length: {glitch_len}") + elif (glitch_len > UPPER_GLITCH_LEN): + UPPER_GLITCH_LEN += INCREMENT_LEN + else: + glitch_len = LOWER_GLITCH_LEN # Reset glitch length + trigger_repeats += INCREMENT_REPEAT # Increment trigger repeats + print_info(f"Glitch length reset. Incrementing trigger repeats: {trigger_repeats}") + else: + if trigger_repeats < UPPER_GLITCH_REPEAT: + trigger_repeats += INCREMENT_REPEAT + print_info(f"Incrementing trigger repeats: {trigger_repeats}") + else: + if(glitch_len == UPPER_GLITCH_LEN): + trigger_repeats = LOWER_GLITCH_REPEAT # Reset trigger repeats + else: + trigger_repeats = LOWER_GLITCH_REPEAT + glitch_len += INCREMENT_LEN # Increment glitch length + print_info(f"Trigger repeats reset. Incrementing glitch length: {glitch_len}") + + + elapsed_time = format_elapsed_time(time.time() - start_time) + print_table(glitch_len, trigger_repeats, delay_time, elapsed_time) + # To print the last 3 messages + print_last_x_messages(10) + + if time.time() - last_restart_time >= restart_interval: + print_info(f"10 min mark. Setting glitch length: 80 and restarting device") + UPPER_GLITCH_LEN = 80 + #restartDeviceAndChall() + last_restart_time = time.time() + +def execute_scope_script(glitch_len, trigger_repeats, delay): + s.glitch.repeat = glitch_len + s.glitch.ext_offset = delay + for _ in range(trigger_repeats): + s.trigger() + +def print_banner(): + print(" ___ _ _ _ _ _ _ ") + print(" / __| (_) |_ __| |_ ___ ___ ___ _ __ __ _| |_(_)__ ") + print(" | (_ | | | _/ _| ' \\___/ _ \\___| ' \\/ _` | _| / _|") + print(" \\___|_|_|\\__\\__|_||_| \\___/ |_|_|_\\__,_|\\__|_\\__|") + +if __name__ == "__main__": + print_info("Starting Program") + s = Scope() + read_serial() \ No newline at end of file