
Chipmonk with NUT to event script power outages
Ah, shit. The power went out.
So you just found the key, almost have the exploit at a PoC state where it fin… Wait what? The power went out! You just lost your last 10 minutes in between commits. This doesn’t happen if you have a UPS. Even when you do have a UPS, a device that keeps the power on to your most important devices during a power outage for a short while (mine, around 45 minutes) using a battery, you probably want your system to be able to back up it’s most important work and then send a shutdown signal, to shut everything down cleanly and avoid data loss.
Tip!: This article pairs well with our other article on backing up your data autonomously!
Chipmonk
Watch what Chipmonk does by default!
The chipmonk code is pretty short and to the point:
#!/bin/bash
# # # Chipmonk
# # # Author: Marshall Whittaker / oxagast
# # # Version: 2.0a
# # # NUT (Network UPS Tools) Visual Power Dialog
# Here you can change the location where Chipmonk will log to.
logloc=/var/log/nut
# The below three functions are for adding user defined scripts!
# I recommend leaving ther placeholders where they are, they are
# innoculous, but the script doesn't work correctly without them
# if nothing else is in the brackets.
function line_power()
{
:
}
function on_battery()
{
:
}
function low_battery()
{
:
}
# Primary functions start here
# Called by trap on a shutdown signal
function clean_up()
{
echo "Running cleanup, killing upslog..."
pkill upslog
rm /tmp/ups.status.$pid
}
# This is for starting and logging things to our log location (default /var/log/nut/)
function log_ups()
{
long_format='%host% %upshost% %time @Y-@M-@d @H:@M% STA:%VAR ups.status% CRG:%VAR battery.charge% INP:%VAR input.voltage% LO
D:%VAR ups.load% TMP:%VAR ups.temperature%'
state='%VAR ups.status%'
if [[ -d $logloc ]]; then
touch "$logloc/ups.log"
if [[ -f "$logloc/ups.log" ]]; then
upslog -l "$logloc/ups.log" -s $model -f "$long_format"
else
echo "Your $logloc is not writable by you."
fi
fi
upslog -l /tmp/ups.status.$pid -s $model -f "$state"
}
# Calls kdialog on UPS state changes
function popup()
{
trap clean_up EXIT
f="/tmp/ups.status.$pid"
powerline=$(<"$f")
inotifywait -m -e modify "$f" --format "%e" | while read -r event 2>/dev/null; do
if [ "$event" == "MODIFY" ]; then
prev="$powerline"
powerline=$(cat "$f" | tail -n 1)
if [[ "$powerline" != "$prev" ]]; then
if [[ $last != $powerline ]]; then
if [[ $powerline == "OL" ]]; then
kdialog --icon "battery-full-charging" --passivepopup "Notice: UPS $model now on line power." 30
line_power
fi
if [[ $powerline == "OB" ]]; then
kdialog --icon "battery-low" --passivepopup "Warning: UPS $model now on battery power." 30
on_battery
fi
if [[ $powerline == "LB" ]]; then
kdialog --icon "battery-caution" --passivepopup "Critical: UPS $model now has a low battery!" 30
low_battery
fi
fi
last=$powerline
fi
fi
done
}
# startup and config initilization
echo "# # # Chipmonk # # #"
echo "NUT (Network UPS Tools) Visual Power Dialogs"
echo "Author: Marshall Whittaker / oxagast"
logperm=2
pid=$$
if [[ "$#" -gt 1 ]]; then
echo "You need to specify the NUT configured UPS model@hostname: "
echo " chipmonk SK600@gotham"
exit 1
fi
if [[ "$#" -eq 0 ]]; then
model=$(grep "[MODEL]" -A 1 ~/.chipmonk | tail -n 1 | tr -d '\n')
if [ $(echo $model | grep ".@." | wc -l) -eq 1 ]; then
log_ups
popup
fi
else
if [[ "$#" -eq 1 ]]; then
model=$1
if [ $(echo $model | grep ".@." | wc -l) -eq 1 ]; then
echo "[MODEL]" >~/.chipmonk
echo $model >>~/.chipmonk
log_ups
popup
fi
fi
echo "You need to specify the NUT configured UPS model@hostname: "
echo " chipmonk SK600@gotham"
exit 1
fi
Here I use NUT (Network UPS Tools), in combination with some code I wrote called Chipmonk that monitors UPS power events. Chipmonk monitors NUT logs and then notifies the user that an event is in play foremost. We do this using kdialog.
Logs
Chipmonk uses one log to monitor events only, and another log is used for the user to review. The user review log looks something like this:
jerkon SK600@jerkon 2022-17-15 13:17 STA:OL CRG:NA INP:121.8 LOD:25 TMP:NA
jerkon SK600@jerkon 2022-17-15 13:17 STA:OL CRG:NA INP:121.8 LOD:28 TMP:NA
jerkon SK600@jerkon 2022-18-15 13:18 STA:OB CRG:NA INP:5.2 LOD:30 TMP:NA
jerkon SK600@jerkon 2022-18-15 13:18 STA:OB CRG:NA INP:5.2 LOD:30 TMP:NA
jerkon SK600@jerkon 2022-26-15 13:26 STA:OB CRG:NA INP:5.2 LOD:30 TMP:NA
jerkon SK600@jerkon 2022-26-15 13:26 STA:OL CRG:NA INP:121.8 LOD:25 TMP:NA
Which gives you your monitoring machine’s hostname, the name of the UPS, and what machine it is currently monitoring (NUT can monitor multiple machines), date, time, UPS status, charge left, input voltage, current system load, and battery temperature, in that order.
The status can be:
1 2 3 | OL - On line power OB - On battery power LB - Low battery power |
I believe there are a few other more obscure statuses that I will include io chipmonk eventually.
User Defined
In Chipmonk, near the top of the code, you will see three functions corresponding to the UPS status.
You are free to script within these brackets, and it should do what you want around the system (like backup/save files, etc).
Fun Fact!: You can do this on lines before or after the
token, however, I suggest not removing the token, as without a NOOP the function breaks the entire script if there is nothing else within the brackets.1
:
Conclusion
Hope you now have a safer hacking experience in a power outage-prone area. You can email me with any questions or comments about this code. Feature requests are also welcome!
If you enjoy my work, sponsor or hire me! I work hard keeping oxasploits running!
Bitcoin Address:
bc1qq7vvwfe7760s3dm8uq28seck465h3tqp3fjq4l
Thank you so much and happy hacking!