From fcea3ab560e5c7efc717d54315677d432c646e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rune=20Lang=C3=B8y?= Date: Thu, 28 Sep 2023 11:37:03 +0200 Subject: [PATCH] Start jupyter notebook with no default page --- ...CWNano to Bypass Password-checkpoint.ipynb | 301 +++++++++++++++ ...e Glitching CWNano Mod Th-checkpoint.ipynb | 350 ++++++++++++++++++ .../simpleserial-glitch-checkpoint.c | 190 ++++++++++ ...ching with CWNano to Bypass Password.ipynb | 301 +++++++++++++++ jupyter/Voltage Glitching CWNano Mod Th.ipynb | 65 +--- jupyter/simpleserial-glitch.c | 190 ++++++++++ jupyter/thonny_start_jupiter.bat | 3 +- 7 files changed, 1338 insertions(+), 62 deletions(-) create mode 100644 jupyter/.ipynb_checkpoints/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password-checkpoint.ipynb create mode 100644 jupyter/.ipynb_checkpoints/Voltage Glitching CWNano Mod Th-checkpoint.ipynb create mode 100644 jupyter/.ipynb_checkpoints/simpleserial-glitch-checkpoint.c create mode 100644 jupyter/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password.ipynb create mode 100644 jupyter/simpleserial-glitch.c diff --git a/jupyter/.ipynb_checkpoints/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password-checkpoint.ipynb b/jupyter/.ipynb_checkpoints/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password-checkpoint.ipynb new file mode 100644 index 0000000..6c9afb4 --- /dev/null +++ b/jupyter/.ipynb_checkpoints/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password-checkpoint.ipynb @@ -0,0 +1,301 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Part 2, Topic 2: Voltage Glitching to Bypass Password" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**SUMMARY:** *We've seen how voltage glitching can be used to corrupt calculations, just like clock glitching. Let's continue on and see if it can also be used to break past a password check.*\n", + "\n", + "**LEARNING OUTCOMES:**\n", + "\n", + "* Applying glitch to breaj password check\n", + "* Checking for success and failure when glitching" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function password returns the vallue of passok.
\n", + "If password is wrong 0 is rerurned
\n", + "If password is correct 1 is rerurned
\n", + "\n", + "```C\n", + "/*src: https://github.com/newaetech/chipwhisperer/blob/develop/hardware/victims/firmware/simpleserial-glitch/simpleserial-glitch.c*/\n", + "\n", + "/*Line 74 .. */\n", + "uint8_t password(uint8_t* pw, uint8_t len)\n", + "\n", + "{\n", + " char passwd[] = \"touch\";\n", + " char passok = 1;\n", + " int cnt;\n", + "\n", + " trigger_high();\n", + "\n", + " //Simple test - doesn't check for too-long password!\n", + " for(cnt = 0; cnt < 5; cnt++){\n", + " if (pw[cnt] != passwd[cnt]){\n", + " passok = 0;\n", + " }\n", + " }\n", + "\n", + " trigger_low();\n", + "\n", + " simpleserial_put('r', 1, (uint8_t*)&passok);\n", + " return 0x00;\n", + "}\n", + "```\n", + "\n", + "### Glitch Hardware" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SCOPETYPE = 'CWNANO'\n", + "PLATFORM = 'CWNANO'\n", + "SS_VER = 'SS_VER_2_1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%run \"Setup_Generic.ipynb\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Program the Victim microcontroller STM32F04xxx
\n", + "using .hex output from the the C - file : **[simpleserial-glitch.c](http://localhost:8888/edit/simpleserial-glitch.c)** \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fw_path=\"simpleserial-glitch-CWNANO.hex\"\n", + "cw.program_target(scope, prog, fw_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ret = \"\"\n", + "target.flush()\n", + "reset_target(scope)\n", + "time.sleep(0.001)\n", + "num_char = target.in_waiting()\n", + "while num_char > 0:\n", + " ret += target.read(timeout=10)\n", + " time.sleep(0.01)\n", + " num_char = target.in_waiting()\n", + "print(ret)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope.io.clkout = 7.5E6\n", + "def reboot_flush(): \n", + " scope.io.nrst = False\n", + " time.sleep(0.05)\n", + " scope.io.nrst = \"high_z\"\n", + " time.sleep(0.05)\n", + " #Flush garbage too\n", + " target.flush()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Do glitch loop\n", + "reboot_flush()\n", + "pw = bytearray([0x74, 0x6F, 0x75, 0x63, 0x68])\n", + "target.simpleserial_write('p', pw)\n", + "\n", + "val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n", + "valid = val['valid']\n", + "if valid:\n", + " response = val['payload']\n", + " raw_serial = val['full_response']\n", + " error_code = val['rv']\n", + "\n", + "print(val)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pylab as plt\n", + "import chipwhisperer.common.results.glitch as glitch\n", + "gc = glitch.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"repeat\", \"ext_offset\"])\n", + "gc.display_stats()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib ipympl \n", + "import matplotlib.pylab as plt\n", + "fig = plt.figure()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from importlib import reload\n", + "import chipwhisperer.common.results.glitch as glitch\n", + "from tqdm.notebook import tqdm\n", + "import re\n", + "import struct\n", + "\n", + "g_step = 1\n", + "\n", + "gc.set_global_step(g_step)\n", + "gc.set_range(\"repeat\", 1, 3)\n", + "gc.set_range(\"ext_offset\", 1, 50)\n", + "\n", + "gc.set_global_step(1)\n", + "\n", + "reboot_flush()\n", + "sample_size = 1\n", + "scope.glitch.repeat = 0\n", + "broken = False\n", + "\n", + "for glitch_settings in gc.glitch_values():\n", + " scope.glitch.repeat = glitch_settings[0]\n", + " scope.glitch.ext_offset = glitch_settings[1]\n", + " if broken:\n", + " break\n", + " for i in range(50):\n", + " scope.arm()\n", + " target.simpleserial_write('p', bytearray([0]*5))\n", + " ret = scope.capture()\n", + " \n", + " if ret:\n", + " print('Timeout - no trigger')\n", + " gc.add(\"reset\", (scope.glitch.repeat, scope.glitch.ext_offset))\n", + " plt.plot(scope.glitch.ext_offset, scope.glitch.repeat, 'xr', alpha=1)\n", + " fig.canvas.draw()\n", + "\n", + " #Device is slow to boot?\n", + " reboot_flush()\n", + "\n", + " else:\n", + " val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n", + " if val['valid'] is False:\n", + " gc.add(\"reset\", (scope.glitch.repeat, scope.glitch.ext_offset))\n", + " plt.plot(scope.glitch.ext_offset, scope.glitch.repeat, 'xr', alpha=1)\n", + " fig.canvas.draw()\n", + " reboot_flush()\n", + " else:\n", + " if val['payload'] == bytearray([1]): #for loop check\n", + " broken = True\n", + " gc.add(\"success\", (scope.glitch.repeat, scope.glitch.ext_offset))\n", + " print(val)\n", + " print(val['payload'])\n", + " print(scope.glitch.repeat, scope.glitch.ext_offset)\n", + " print(\"🐙\", end=\"\")\n", + " plt.plot(scope.glitch.ext_offset, scope.glitch.repeat, '+g', alpha=1)\n", + " fig.canvas.draw()\n", + " break\n", + " else:\n", + " gc.add(\"normal\", (scope.glitch.repeat, scope.glitch.ext_offset))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope.dis()\n", + "target.dis()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert broken is True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/jupyter/.ipynb_checkpoints/Voltage Glitching CWNano Mod Th-checkpoint.ipynb b/jupyter/.ipynb_checkpoints/Voltage Glitching CWNano Mod Th-checkpoint.ipynb new file mode 100644 index 0000000..8b17679 --- /dev/null +++ b/jupyter/.ipynb_checkpoints/Voltage Glitching CWNano Mod Th-checkpoint.ipynb @@ -0,0 +1,350 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# This is a small mod of the Newaetech tutorial Introduction to Voltage Glitchin for CW-Nano\n", + "The sole intent for this mod is to enable the students at [University of South-eastern Noway](www.usn.no) to be able to run the example on the lab \\\n", + "Please check [https://github.com/newaetech](https://github.com/newaetech) for utdates :) \\\n", + "[original src:](https://github.com/newaetech/chipwhisperer-jupyter/blob/c940073159c8032877e9f7b9ef852b3662c4ec02/courses/fault101/SOLN_Fault%202_1B%20-%20Introduction%20to%20Voltage%20Glitching%20with%20CWNano.ipynb)\n", + "The examle could be runned using jupyter but requres some python libraries like: chipwhisperer , matplotlib ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Part 2, Topic 2: Introduction to Voltage Glitching (MAIN)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**SUMMARY:** *While it's not as sophisticated as the ChipWhisperer Lite or ChipWhisperer Pro's glitch hardware, the ChipWhisperer Nano is also capable of glitching. In this lab, we'll do some simple glitch tests on the Nano's target board, showing how to scan through glitch settings and seeing what effect it has on the hardware.*\n", + "\n", + "**LEARNING OUTCOMES:**\n", + "\n", + "* Understanding how voltage glitching can be used to disrupt a target's operation\n", + "* Scanning glitch settings to determine successful ones" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Digital hardware devices have certain voltage and clock requirements to function properly. If these requirements are not met, the device can fail to function, or even be damage. By shorting the voltage pins of a microcontroller for controlled, short periods of time, we can cause it to behave erratically, clearning registers and skipping instructions. Such attacks can be immensely powerful in practice. Consider for example the following code from [newaetech - simpleserial-glitch.c ](https://github.com/newaetech/chipwhisperer/blob/develop/hardware/victims/firmware/simpleserial-glitch/simpleserial-glitch.c) :\n", + "\n", + "```C\n", + "/*src: https://github.com/newaetech/chipwhisperer/blob/develop/hardware/victims/firmware/simpleserial-glitch/simpleserial-glitch.c*/\n", + "/*Line 32 .. (+ small mod..)*/\n", + "uint8_t glitch_loop(uint8_t* in)\n", + "{\n", + " volatile uint16_t i, j;\n", + " volatile uint32_t cnt;\n", + " cnt = 0;\n", + " \n", + " trigger_high(); /* Chipwhisper starts VDD Glitching */\n", + " /* One of the output pins is set high */\n", + "\n", + " /* Glitch Victim Code */\n", + " for(i=0; i<50; i++){\n", + " for(j=0; j<50; j++){\n", + " cnt++;\n", + " }\n", + " }\n", + " \n", + " trigger_low(); /* Chipwhisper Stop VDD Glitching (Dont kill the serial output..) */\n", + " \n", + " /* Python listen for serial data using */\n", + " /* val = target.simpleserial_read_witherrors('r', 4, glitch_timeout=100) */\n", + " simpleserial_put('r', 4, (uint8_t*)&cnt); /* Python reieves val['payload'] */\n", + "\n", + " /* Validate the result before exiting */\n", + " return (cnt != 2500); /* Python recieves val['valid'] True/False */\n", + "```\n", + "\n", + "### Glitch Hardware\n", + "\n", + "The ChipWhisperer Nano's glitch setup is pretty simple. Like its bigger brothers, the Lite and the Pro, it uses a MOSFET to short the microcontroller's voltage supply to ground:\n", + "Some new chip-whisper nano cards needs to be modifyed to produce sucessfull glitching.\n", + "( The new resistor was 5.6 Ohm [more info on github](https://github.com/newaetech/chipwhisperer/issues/419#issuecomment-1262053220)\n", + "\n", + "![Original vs Modifyed CW-Nano](./mod_glitch.png)\n", + "\n", + "For the Nano, `Glitch In` is controlled by 2 parameters:\n", + "\n", + "1. `scope.glitch.ext_offset` - The glitch will be inserted roughly `8.3ns * scope.glitch.ext_offset`\n", + "1. `scope.glitch.repeat` - The glitch will be inserted for roughly `8.3ns * scope.glitch.repeat`\n", + "\n", + "During this lab, we'll be varying these parameters to see if we can get the target to mess up a calculation that it's doing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SCOPETYPE = 'CWNANO'\n", + "PLATFORM = 'CWNANO'\n", + "SS_VER = 'SS_VER_2_1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%run \"Setup_Generic.ipynb\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Program the Victim microcontroller STM32F04xxx
\n", + "using .hex output from the the C - file : **[simpleserial-glitch.c](http://localhost:8888/edit/simpleserial-glitch.c)** \n" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "fw_path=\"simpleserial-glitch-CWNANO.hex\"\n", + "cw.program_target(scope, prog, fw_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope.io.clkout = 7.5E6\n", + "def reboot_flush(): \n", + " scope.io.nrst = False\n", + " time.sleep(0.05)\n", + " scope.io.nrst = \"high_z\"\n", + " time.sleep(0.05)\n", + " #Flush garbage too\n", + " target.flush()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import struct\n", + "reboot_flush()\n", + "scope.glitch.repeat = 160\n", + "scope.glitch.ext_offset =100\n", + "\n", + "scope.arm()\n", + "target.simpleserial_write(\"g\", bytearray([]))\n", + "scope.capture()\n", + "val = target.simpleserial_read_witherrors('r', 4, glitch_timeout=100)#For loop check\n", + "valid = val['valid']\n", + "if valid:\n", + " response = val['payload']\n", + " raw_serial = val['full_response']\n", + " error_code = val['rv']\n", + " gcnt = struct.unpack(\" 0: \n", + " print(\"successes = {}, resets = {}, repeat = {}, ext_offset = {}\".format(successes, resets, scope.glitch.repeat, scope.glitch.ext_offset))\n", + "print(\"Done glitching\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib notebook\n", + "gc.results.plot_2d(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope.dis()\n", + "target.dis()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unlike the other ChipWhisperers, the Nano doesn't have sychronous glitching. This means that `ext_offset` is a mixture of both the offset within the clock cycle, which affects glitch success, and ext_offset, which affects which instruction is being glitched. As such, ext_offset settings you find in this lab won't be directly applicable to other labs. That being said, good ranges for repeat and the success rate of glitches still gives valuable information that you can apply to other labs." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/jupyter/.ipynb_checkpoints/simpleserial-glitch-checkpoint.c b/jupyter/.ipynb_checkpoints/simpleserial-glitch-checkpoint.c new file mode 100644 index 0000000..a672e93 --- /dev/null +++ b/jupyter/.ipynb_checkpoints/simpleserial-glitch-checkpoint.c @@ -0,0 +1,190 @@ +/* + This file is part of the ChipWhisperer Example Targets + Copyright (C) 2012-2020 NewAE Technology Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "hal.h" +#include +#include + +#include "simpleserial.h" + +//uint8_t infinite_loop(uint8_t* in); +//uint8_t glitch_loop(uint8_t* in); +//uint8_t password(uint8_t* pw); + +#if SS_VER == SS_VER_2_1 +uint8_t glitch_loop(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* in) +#else +uint8_t glitch_loop(uint8_t* in, uint8_t len) +#endif +{ + volatile uint16_t i, j; + volatile uint32_t cnt; + cnt = 0; + trigger_high(); + for(i=0; i<50; i++){ + for(j=0; j<50; j++){ + cnt++; + } + } + trigger_low(); + simpleserial_put('r', 4, (uint8_t*)&cnt); +#if SS_VER == SS_VER_2_1 + return (cnt != 2500) ? 0x10 : 0x00; +#else + return (cnt != 2500); +#endif +} + +#if SS_VER == SS_VER_2_1 +uint8_t glitch_comparison(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* in) +#else +uint8_t glitch_comparison(uint8_t* in, uint8_t len) +#endif +{ + uint8_t ok = 5; + trigger_high(); + if (*in == 0xA2){ + ok = 1; + } else { + ok = 0; + } + trigger_low(); + simpleserial_put('r', 1, (uint8_t*)&ok); + return 0x00; +} + +#if SS_VER == SS_VER_2_1 +uint8_t password(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* pw) +#else +uint8_t password(uint8_t* pw, uint8_t len) +#endif +{ + char passwd[] = "touch"; + char passok = 1; + int cnt; + + trigger_high(); + + //Simple test - doesn't check for too-long password! + for(cnt = 0; cnt < 5; cnt++){ + if (pw[cnt] != passwd[cnt]){ + passok = 0; + } + } + + trigger_low(); + + simpleserial_put('r', 1, (uint8_t*)&passok); + return 0x00; +} + +#if SS_VER == SS_VER_2_1 +uint8_t infinite_loop(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* in) +#else +uint8_t infinite_loop(uint8_t* in, uint8_t len) +#endif +{ + led_ok(1); + led_error(0); + + //Some fake variable + volatile uint8_t a = 0; + + //External trigger logic + trigger_high(); + trigger_low(); + + //Should be an infinite loop + while(a != 2){ + ; + } + + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + + putch('r'); + putch('B'); + putch('R'); + putch('E'); + putch('A'); + putch('K'); + putch('O'); + putch('U'); + putch('T'); + putch('\n'); + + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + + return 0; +} + +int main(void) +{ + + platform_init(); + + + init_uart(); + + //led_error(0); + //while(1) ; // break--- + + trigger_setup(); + + + + /* Device reset detected */ + putch('r'); + putch('R'); + putch('E'); + putch('S'); + putch('E'); + putch('T'); + putch(' '); + putch(' '); + putch(' '); + putch('\n'); + + + led_error(0); + simpleserial_init(); + simpleserial_addcmd('g', 0, glitch_loop); + simpleserial_addcmd('c', 1, glitch_comparison); + #if SS_VER == SS_VER_2_1 + simpleserial_addcmd(0x01, 5, password); + #else + simpleserial_addcmd('p', 5, password); + #endif + simpleserial_addcmd('i', 0, infinite_loop); + while(1) + simpleserial_get(); +} diff --git a/jupyter/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password.ipynb b/jupyter/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password.ipynb new file mode 100644 index 0000000..80c01dc --- /dev/null +++ b/jupyter/SOLN_Fault 2_2B - Voltage Glitching with CWNano to Bypass Password.ipynb @@ -0,0 +1,301 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Part 2, Topic 2: Voltage Glitching to Bypass Password" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**SUMMARY:** *We've seen how voltage glitching can be used to corrupt calculations, just like clock glitching. Let's continue on and see if it can also be used to break past a password check.*\n", + "\n", + "**LEARNING OUTCOMES:**\n", + "\n", + "* Applying glitch to break password check\n", + "* Checking for success and failure when glitching" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function password returns the vallue of passok.
\n", + "If password is wrong 0 is rerurned
\n", + "If password is correct 1 is rerurned
\n", + "\n", + "```C\n", + "/*src: https://github.com/newaetech/chipwhisperer/blob/develop/hardware/victims/firmware/simpleserial-glitch/simpleserial-glitch.c*/\n", + "\n", + "/*Line 74 .. */\n", + "uint8_t password(uint8_t* pw, uint8_t len)\n", + "\n", + "{\n", + " char passwd[] = \"touch\";\n", + " char passok = 1;\n", + " int cnt;\n", + "\n", + " trigger_high();\n", + "\n", + " //Simple test - doesn't check for too-long password!\n", + " for(cnt = 0; cnt < 5; cnt++){\n", + " if (pw[cnt] != passwd[cnt]){\n", + " passok = 0;\n", + " }\n", + " }\n", + "\n", + " trigger_low();\n", + "\n", + " simpleserial_put('r', 1, (uint8_t*)&passok);\n", + " return 0x00;\n", + "}\n", + "```\n", + "\n", + "### Glitch Hardware" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SCOPETYPE = 'CWNANO'\n", + "PLATFORM = 'CWNANO'\n", + "SS_VER = 'SS_VER_2_1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%run \"Setup_Generic.ipynb\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Program the Victim microcontroller STM32F04xxx
\n", + "using .hex output from the the C - file : **[simpleserial-glitch.c](http://localhost:8888/edit/simpleserial-glitch.c)** \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fw_path=\"simpleserial-glitch-CWNANO.hex\"\n", + "cw.program_target(scope, prog, fw_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ret = \"\"\n", + "target.flush()\n", + "reset_target(scope)\n", + "time.sleep(0.001)\n", + "num_char = target.in_waiting()\n", + "while num_char > 0:\n", + " ret += target.read(timeout=10)\n", + " time.sleep(0.01)\n", + " num_char = target.in_waiting()\n", + "print(ret)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope.io.clkout = 7.5E6\n", + "def reboot_flush(): \n", + " scope.io.nrst = False\n", + " time.sleep(0.05)\n", + " scope.io.nrst = \"high_z\"\n", + " time.sleep(0.05)\n", + " #Flush garbage too\n", + " target.flush()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Do glitch loop\n", + "reboot_flush()\n", + "pw = bytearray([0x74, 0x6F, 0x75, 0x63, 0x68])\n", + "target.simpleserial_write('p', pw)\n", + "\n", + "val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n", + "valid = val['valid']\n", + "if valid:\n", + " response = val['payload']\n", + " raw_serial = val['full_response']\n", + " error_code = val['rv']\n", + "\n", + "print(val)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pylab as plt\n", + "import chipwhisperer.common.results.glitch as glitch\n", + "gc = glitch.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"repeat\", \"ext_offset\"])\n", + "gc.display_stats()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib ipympl \n", + "import matplotlib.pylab as plt\n", + "fig = plt.figure()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from importlib import reload\n", + "import chipwhisperer.common.results.glitch as glitch\n", + "from tqdm.notebook import tqdm\n", + "import re\n", + "import struct\n", + "\n", + "g_step = 1\n", + "\n", + "gc.set_global_step(g_step)\n", + "gc.set_range(\"repeat\", 1, 3)\n", + "gc.set_range(\"ext_offset\", 1, 50)\n", + "\n", + "gc.set_global_step(1)\n", + "\n", + "reboot_flush()\n", + "sample_size = 1\n", + "scope.glitch.repeat = 0\n", + "broken = False\n", + "\n", + "for glitch_settings in gc.glitch_values():\n", + " scope.glitch.repeat = glitch_settings[0]\n", + " scope.glitch.ext_offset = glitch_settings[1]\n", + " if broken:\n", + " break\n", + " for i in range(50):\n", + " scope.arm()\n", + " target.simpleserial_write('p', bytearray([0]*5))\n", + " ret = scope.capture()\n", + " \n", + " if ret:\n", + " print('Timeout - no trigger')\n", + " gc.add(\"reset\", (scope.glitch.repeat, scope.glitch.ext_offset))\n", + " plt.plot(scope.glitch.ext_offset, scope.glitch.repeat, 'xr', alpha=1)\n", + " fig.canvas.draw()\n", + "\n", + " #Device is slow to boot?\n", + " reboot_flush()\n", + "\n", + " else:\n", + " val = target.simpleserial_read_witherrors('r', 1, glitch_timeout=10)#For loop check\n", + " if val['valid'] is False:\n", + " gc.add(\"reset\", (scope.glitch.repeat, scope.glitch.ext_offset))\n", + " plt.plot(scope.glitch.ext_offset, scope.glitch.repeat, 'xr', alpha=1)\n", + " fig.canvas.draw()\n", + " reboot_flush()\n", + " else:\n", + " if val['payload'] == bytearray([1]): #for loop check\n", + " broken = True\n", + " gc.add(\"success\", (scope.glitch.repeat, scope.glitch.ext_offset))\n", + " print(val)\n", + " print(val['payload'])\n", + " print(scope.glitch.repeat, scope.glitch.ext_offset)\n", + " print(\"🐙\", end=\"\")\n", + " plt.plot(scope.glitch.ext_offset, scope.glitch.repeat, '+g', alpha=1)\n", + " fig.canvas.draw()\n", + " break\n", + " else:\n", + " gc.add(\"normal\", (scope.glitch.repeat, scope.glitch.ext_offset))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scope.dis()\n", + "target.dis()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert broken is True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/jupyter/Voltage Glitching CWNano Mod Th.ipynb b/jupyter/Voltage Glitching CWNano Mod Th.ipynb index 444ad17..8b17679 100644 --- a/jupyter/Voltage Glitching CWNano Mod Th.ipynb +++ b/jupyter/Voltage Glitching CWNano Mod Th.ipynb @@ -115,14 +115,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Program the Victim microcontroller STM32F04xxx" + "Program the Victim microcontroller STM32F04xxx
\n", + "using .hex output from the the C - file : **[simpleserial-glitch.c](http://localhost:8888/edit/simpleserial-glitch.c)** \n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "raw", "metadata": {}, - "outputs": [], "source": [ "fw_path=\"simpleserial-glitch-CWNANO.hex\"\n", "cw.program_target(scope, prog, fw_path)" @@ -228,35 +227,7 @@ "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:377) Unexpected start to command 82\n", - "(ChipWhisperer Target WARNING|File SimpleSerial2.py:410) Unexpected length 69, 4\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Done glitching\n" - ] - } - ], + "outputs": [], "source": [ "from importlib import reload\n", "import chipwhisperer.common.results.glitch as glitch\n", @@ -353,34 +324,6 @@ "source": [ "Unlike the other ChipWhisperers, the Nano doesn't have sychronous glitching. This means that `ext_offset` is a mixture of both the offset within the clock cycle, which affects glitch success, and ext_offset, which affects which instruction is being glitched. As such, ext_offset settings you find in this lab won't be directly applicable to other labs. That being said, good ranges for repeat and the success rate of glitches still gives valuable information that you can apply to other labs." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/jupyter/simpleserial-glitch.c b/jupyter/simpleserial-glitch.c new file mode 100644 index 0000000..a672e93 --- /dev/null +++ b/jupyter/simpleserial-glitch.c @@ -0,0 +1,190 @@ +/* + This file is part of the ChipWhisperer Example Targets + Copyright (C) 2012-2020 NewAE Technology Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "hal.h" +#include +#include + +#include "simpleserial.h" + +//uint8_t infinite_loop(uint8_t* in); +//uint8_t glitch_loop(uint8_t* in); +//uint8_t password(uint8_t* pw); + +#if SS_VER == SS_VER_2_1 +uint8_t glitch_loop(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* in) +#else +uint8_t glitch_loop(uint8_t* in, uint8_t len) +#endif +{ + volatile uint16_t i, j; + volatile uint32_t cnt; + cnt = 0; + trigger_high(); + for(i=0; i<50; i++){ + for(j=0; j<50; j++){ + cnt++; + } + } + trigger_low(); + simpleserial_put('r', 4, (uint8_t*)&cnt); +#if SS_VER == SS_VER_2_1 + return (cnt != 2500) ? 0x10 : 0x00; +#else + return (cnt != 2500); +#endif +} + +#if SS_VER == SS_VER_2_1 +uint8_t glitch_comparison(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* in) +#else +uint8_t glitch_comparison(uint8_t* in, uint8_t len) +#endif +{ + uint8_t ok = 5; + trigger_high(); + if (*in == 0xA2){ + ok = 1; + } else { + ok = 0; + } + trigger_low(); + simpleserial_put('r', 1, (uint8_t*)&ok); + return 0x00; +} + +#if SS_VER == SS_VER_2_1 +uint8_t password(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* pw) +#else +uint8_t password(uint8_t* pw, uint8_t len) +#endif +{ + char passwd[] = "touch"; + char passok = 1; + int cnt; + + trigger_high(); + + //Simple test - doesn't check for too-long password! + for(cnt = 0; cnt < 5; cnt++){ + if (pw[cnt] != passwd[cnt]){ + passok = 0; + } + } + + trigger_low(); + + simpleserial_put('r', 1, (uint8_t*)&passok); + return 0x00; +} + +#if SS_VER == SS_VER_2_1 +uint8_t infinite_loop(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t* in) +#else +uint8_t infinite_loop(uint8_t* in, uint8_t len) +#endif +{ + led_ok(1); + led_error(0); + + //Some fake variable + volatile uint8_t a = 0; + + //External trigger logic + trigger_high(); + trigger_low(); + + //Should be an infinite loop + while(a != 2){ + ; + } + + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + + putch('r'); + putch('B'); + putch('R'); + putch('E'); + putch('A'); + putch('K'); + putch('O'); + putch('U'); + putch('T'); + putch('\n'); + + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + led_error(1); + + return 0; +} + +int main(void) +{ + + platform_init(); + + + init_uart(); + + //led_error(0); + //while(1) ; // break--- + + trigger_setup(); + + + + /* Device reset detected */ + putch('r'); + putch('R'); + putch('E'); + putch('S'); + putch('E'); + putch('T'); + putch(' '); + putch(' '); + putch(' '); + putch('\n'); + + + led_error(0); + simpleserial_init(); + simpleserial_addcmd('g', 0, glitch_loop); + simpleserial_addcmd('c', 1, glitch_comparison); + #if SS_VER == SS_VER_2_1 + simpleserial_addcmd(0x01, 5, password); + #else + simpleserial_addcmd('p', 5, password); + #endif + simpleserial_addcmd('i', 0, infinite_loop); + while(1) + simpleserial_get(); +} diff --git a/jupyter/thonny_start_jupiter.bat b/jupyter/thonny_start_jupiter.bat index 7332351..02c85cd 100644 --- a/jupyter/thonny_start_jupiter.bat +++ b/jupyter/thonny_start_jupiter.bat @@ -1 +1,2 @@ -"C:\Program Files (x86)\Thonny\python.exe" -m notebook "Voltage Glitching CWNano Mod Th.ipynb" +"C:\Program Files (x86)\Thonny\python.exe" -m notebook +rem "Voltage Glitching CWNano Mod Th.ipynb"