This commit is contained in:
2024-06-28 04:07:22 -06:00
parent e7bfcd1a78
commit 4da90cf9fe
7 changed files with 77 additions and 30 deletions
+1
View File
@@ -2,3 +2,4 @@
.micropico
PiPicoPATLFGGGGG.code-workspace
main_dev.py
ComicCode-Regular.*
+12
View File
@@ -0,0 +1,12 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
+16 -1
View File
@@ -4,7 +4,7 @@
A tool for simplifying power analysis attacks against other gadgets.
Built on the Raspberry Pi Pico W, it runs a PWM channel to do manual clock control on the nugget you're hacking, and then reads an ADC channel to measure voltage used at each clock cycle.
## Installataion
## Installation
Make sure you have Micropython installed on your Pico W.
Open up your Pico W in your favorite IDE (Thonny and VS Code are commonly used) and upload main.py.
If you're having trouble, see the official [Raspberry Pi Pico W Getting Started Page](https://projects.raspberrypi.org/en/projects/get-started-pico-w)
@@ -75,3 +75,18 @@ For #2, we need to remove the builtin crystal oscilator and replace that connect
For this example, I will describe a firmware decryption power analysis attack.
Scenario: You have and ESP32-S3 based device with flash and bootloader encryption set up on it. You Can remove the RF sheield and get a raw dump of the flash chip with a SOP8 test clip and a programmer, but the data is encrypted.
## Method
1) We disassemble the device to the bare board we're interested in
2) Then remove the RF shield and crystal oscilator from the ESP32-S3 via reflow
3) Clip a SOP8 test clip on the 8pin flash chip and dump the encrypted data with a programmer like a CH431a or T48
4) Set up the breadboard with the Pico W.
5) Place the clock_pulse_pin probe where the crystal oscillator used to be
6) Place power_analysis_pin probe on the rawest vin power spot you can find
7) Run the Pico W (see Usage)
8) Dump serial data to some manner of logger Todo: figure out this tooling
9) Perform statistical attack to dump key! Todo: automate and figure out tooling
Distributed under the [WTFPL - The Do What the Fuck You Want to Public License](http://www.wtfpl.net/)
See [COPYING.txt](COPYING.txt)
![WTFPL](resources/wtfpl.png)
+46 -27
View File
@@ -4,7 +4,7 @@ import machine
import utime
import _thread
import math
import os
#import os
# gpio pin to read power analysis off of (int)
@@ -33,6 +33,7 @@ def do_pwm(outpin = 20, duty_cycle = 0.5, frequency = 2000):
pwm_pin.duty_u16(pwm_duty)
print(f"Clock Pulses Running\n\tGPIO Pin: {outpin}\n\tDuty Cycle: {percent_duty}%\n\tFrequency: {frequency}Hz")
# us of sleep calculate4d by floor(1000000 / (frequency_in_Hz * samples_per_pulse))
def us_samples(frequency, samples_per_pulse):
return math.floor(1000000/(frequency*samples_per_pulse))
@@ -53,52 +54,71 @@ def do_adc(adcpin=28, duty_cycle = 0.5, frequency = 2000, samples_per_pulse = 10
# == HTTP Stuff == #
# HTML template for the webpage
def default_webpage():
template = f"""
header = f"""
<!DOCTYPE html>
<html>
<head>
<title>Power Analysis Tool LFGGGGg</title>
<title>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preload" href="http://10.0.0.80/ComicCode-Regular.woff2" as="font" type="font/woff2" crossorigin>
<style>
body {{
font-family: 'Comic Code';
font-weight: normal;
font-style: normal;
}}
form, div {{
width: 80%;
margin: auto;
}}
h1 {{
font-size: 1.15em;'
}}
form input[type='number'] {{
width: 3.6em;
}}
</style>
</head>
<body>
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
"""
footer = f"""
</body>
</html>
"""
def default_webpage():
template = f"""
{header}
<form action="/action">
<b>Clock Control Config</b><br>
<input id="duty_cycle" name="duty_cycle" type="range" min="0" max="1" step="0.01" value="0.5"> <output id="duty_cycle_output">50%</output> Duty Cycle (% of time clock is on)<br><br>
<input type="number" name="freq" value="2000"> Frequency (Hz aka number of pulses per second)<br><br>
<b>Samplerate Config:</b><br>
<input type="number" id="samples_per_pulse" name="samples_per_pulse" value="5"> Samples Per Manual Clock Pulse<br><br>
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<b>Config:</b><br>
Duty Cycle<br><input id="duty_cycle" name="duty_cycle" type="range" min="0" max="1" step="0.01" value="0.5"> <output id="duty_cycle_output">50%</output><br><br>
Frequency (Hz)<br><input type="number" size="5" name="freq" value="2000"><br><br>
Samples Per Clock Pulse:<br> <input type="number" size="5" id="samples_per_pulse" name="samples_per_pulse" value="5"><br><br>
<input type="submit" value="Go, Baby, Go!">
</form>
<script>
const value = document.querySelector("#duty_cycle_output");
const input = document.querySelector("#duty_cycle");
value.textContent = input.value;
value.textContent = "50%"; // set default for some reason? fuck javascript
input.addEventListener("input", (event) => {{
value.textContent = (event.target.value*100)+"%";
}});
</script>
</body>
</html>
{footer}
"""
return str(template)
# us of sleep calculate4d by floor(1000000 / (frequency_in_Hz * samples_per_pulse))
def running_webpage(outpin = 20, adcpin = 28, duty_cycle = 0.5, frequency = 2000, samples_per_pulse = 100):
dutyy = duty_cycle*100
us_sample = us_samples(frequency, samples_per_pulse)
template = f"""
<!DOCTYPE html>
<html>
<head>
<title>RUNNING - Power Analysis Tool LFGGGGg</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{header}
<div id="sillyrunninfg">
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<h2>WE RUNNING NOWWWWW LFGGGGGGGGGGGGG</h2>
<p>
@@ -110,8 +130,8 @@ def running_webpage(outpin = 20, adcpin = 28, duty_cycle = 0.5, frequency = 2000
Delay Between Samples: <b>{us_sample}us</b><br><br>
<b>LFGGGGGGGG FRONG</b>
</p>
</body>
</html>
</div>
{footer}
"""
return str(template)
@@ -137,7 +157,6 @@ if wlan.status() != 3:
else:
print('Connection successful!')
network_info = wlan.ifconfig()
#print('IP address:', network_info[0])
print(f"\n\nOpen web browser and navigate to http://{network_info[0]}\n\n")
# Set up socket and start listening
@@ -190,7 +209,7 @@ while True:
else:
response = default_webpage()
# Send the HTTP response and close the connection
# Send the HTTP response and close the conn
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
conn.send(response)
conn.close()
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB