Initial, Commit

This commit is contained in:
2024-06-28 02:55:43 -06:00
commit e7bfcd1a78
3 changed files with 281 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
.vscode
.micropico
PiPicoPATLFGGGGG.code-workspace
main_dev.py
+77
View File
@@ -0,0 +1,77 @@
# SillyFilly Pi Pico W Power Analysis Tool
# LFGGGGGGGGGGG
# FRONG
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
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)
## Usage
1) Optional: edit the `power_analysis_pin` and `clock_pulse_pin` variables as you see fit
2) Edit the `ssid` and `password` variables with your wifi name (ssid) and the password
3) Set up the Pico W with pins on a breadboard, connect your power_analysis_pin and clock_pulse pin to the nugget (See Theory and Method)
3) Plug the Pico W to USB of your computer
4) Open the serial terminal of the Pico W
5) Reset the Pico W
6) When the Pico W connects, it will display a message like `Open web browser and navigate to http://x.x.x.x` Open a web browser on the same network and navigate to that address
7) Configure the options on the page to your liking (see below under Options)
## Options
### main.py
`power_analysis_pin`
This is the pin that is reading the power usage from the device
Defaults to GPIO 28
`clock_pulse_pin`
This pin provides the clock signal that you will be using to manually take control of the nuggets clock
Defaults to GPIO 20
`ssid`
This is your wifi network name. Only bgn supported (2.4GHz)
Dont forget the 's around the name
`password`
Your wifi password
Dont forget the 's around the password
### On the Webpage
`Duty Cycle`
The Percentage of the time that the clock is on vs off
50% is by far the most common, it makes a normal square wave and is the default output
for most oscilators that you will be replacing
`Frequency`
Frequency in Hertz (Hz)
How many times per second you want your nuggets clock to pulse
Dont make this too high
`Samples Per Manual Clock Pulse`
This is how many times per clock pulse to sample the nuggets power usage
Dont make this too high
## Hardware Needed
1) Raspberry Pi Pico W or Raspberry Pi Pico WH
2) Pins
3) Breadboard
4) Small capacitior (470uF is fine or anywhere within that range)
5) Wires
6) Optional: spikey probes
## Theory
Power analysis attacks are very simple in concept.
The idea is monitoring the amount of power a device uses very carefully to get some data leaked.
Two things are most important during these attacks:
1) Getting the most accurate, raw read of the power usage at a high sample rate
2) Controlling the clock of the device to slow down the processor enough to get the readings
To accomplish #1, we will get our power reading probe as close to the action of the processor as possible, while als adding a capacitor ground, which will pull any remaining juice out of the system.
For #2, we need to remove the builtin crystal oscilator and replace that connection with our clock pulse probe.
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.
+200
View File
@@ -0,0 +1,200 @@
import network
import socket
import machine
import utime
import _thread
import math
import os
# gpio pin to read power analysis off of (int)
# reads 16bit (0-65535) between 0.0v and 3.3v
# (16 bit is phony, real read is 12 bit)
power_analysis_pin = 28
# output gpio pin generating clock pulse
clock_pulse_pin = 20
# Wi-Fi credentials
ssid = 'your-wifi-name-here'
password = 'yuour-wifi-password-here'
# == Clock Pulse Genertor == #
# starts a pwm
# usage do_pwm(int gpio_pin, float duty_cycle, int hertz frequency, int samples_per_clock_pulse)
def do_pwm(outpin = 20, duty_cycle = 0.5, frequency = 2000):
print('Starting Clock Pulse PWM')
output_pin = machine.Pin(outpin)
pwm_pin = machine.PWM(output_pin)
pwm_pin.freq(frequency)
pwm_duty = math.floor(duty_cycle*65535)
percent_duty = duty_cycle*100
pwm_pin.duty_u16(pwm_duty)
print(f"Clock Pulses Running\n\tGPIO Pin: {outpin}\n\tDuty Cycle: {percent_duty}%\n\tFrequency: {frequency}Hz")
def us_samples(frequency, samples_per_pulse):
return math.floor(1000000/(frequency*samples_per_pulse))
# == Read Value off of device == #
# uses ADC, 16bit output is phony, is actualloy 12bit.
# us of sleep calculate4d by floor(1000000 / (frequency_in_Hz * samples_per_pulse))
def do_adc(adcpin=28, duty_cycle = 0.5, frequency = 2000, samples_per_pulse = 100):
print('Starting voltage reading ADC')
semaphore_thread_adc = _thread.allocate_lock()
analog_value = machine.ADC(adcpin)
us_sample = us_samples(frequency, samples_per_pulse)
while True:
semaphore_thread_adc.acquire()
reading = analog_value.read_u16()
print(reading)
utime.sleep_us(us_sample)
semaphore_thread_adc.release()
# == HTTP Stuff == #
# HTML template for the webpage
def default_webpage():
template = f"""
<!DOCTYPE html>
<html>
<head>
<title>Power Analysis Tool LFGGGGg</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<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>
<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>
"""
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>
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<h2>WE RUNNING NOWWWWW LFGGGGGGGGGGGGG</h2>
<p>
Clock Pulse Pin: <b>{outpin}</b><br>
Power Analysis Pin: <b>{adcpin}</b><br><br>
Frequency: <b>{frequency}Hz</b> (Duty Cycle: <b>{dutyy}%</b>)<br>
Samples Per Pulse: <b>{samples_per_pulse}</b><br>
Delay Between Samples: <b>{us_sample}us</b><br><br>
<b>LFGGGGGGGG FRONG</b>
</p>
</body>
</html>
"""
return str(template)
print("Board Started or Reset\n===========\n\n")
# Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
utime.sleep(1)
# Check if connection is successful
if wlan.status() != 3:
raise RuntimeError('Failed to establish a network connection')
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
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen()
# I like to have the LED on :3
led = machine.Pin('LED', machine.Pin.OUT)
led.value(1)
while True:
try:
conn, addr = s.accept()
request = conn.recv(1024)
request = str(request)
try:
fullreq = request.split()
request = fullreq[1]
except IndexError:
pass
# Process the action page!
if request.startswith('/action?', 0):
# parse the request path to extract da GET vars
req_string = request.split('?')[1]
req_vars = req_string.split('&')
for f in req_vars:
req_split = f.split('=')
# Type strict whitelist for safety and compatibility
if req_split[0] == 'duty_cycle':
duty_cycle_in = float(req_split[1])
elif req_split[0] == 'freq':
freq_in = int(req_split[1])
elif req_split[0] == 'samples_per_pulse':
samples_per_pulse_in = int(req_split[1])
print(f"power_analysis_pin: {power_analysis_pin}\nduty_cycle_in: {duty_cycle_in}\nfreq_in: {freq_in}\nsamples_per_pulse_in:{samples_per_pulse_in}")
# run the clock pulse (PWM) task
do_pwm(clock_pulse_pin, duty_cycle_in, freq_in)
# fork the voltage measuring ADC reading to the second core
_thread.start_new_thread(do_adc, (power_analysis_pin, duty_cycle_in, freq_in, samples_per_pulse_in))
response = running_webpage()
else:
response = default_webpage()
# Send the HTTP response and close the connection
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
conn.send(response)
conn.close()
except OSError as e:
conn.close()
print('Connection closed')