- Why to fuzz SMI handler
- How to -|-
- What next?
SMI handler is a very attractive target for
different kind of privilege escalation attacks, as
it runs in ring -2. This means that it has the
highest privilege level on the CPU.
SMI handler is located in System Management Mode firmware
and is accessible by os via GPIO ports 0xB2/0xB3.
Modern OSes may trigger System Management Interrupts for eg.
power management related reasons.
See https://en.wikipedia.org/wiki/System_Management_Mode for
more detailed explanation.
So, why to fuzz SMI handler? One could assume that firmware code
has been tested a lot before it gets into production, or that
others have found all of the bugs already. That's not the case.
SMM Firmware code often gets hacked together with really little
amount of testing, and is vulnerable to really simple things.
Fuzzing itself only shows us quickly how well does the SMI Handler
deal with invalid input, you still need to either debug the cpu & chipset during
fuzzing, or dump the firmware somehow and reverse engineer it.
Why fuzz then if you have to RE firmware nevertheless? Fuzzing is an easy
way for lazy people like me to check if there are bugs in somewhat fast way.
It also does some funny things that might cause problems, that still may go
unseen while reverse engineering / doing code review.
So, how exactly do we fuzz an SMI handler? As this is the 1st part of
the series we'll go easy and lightweight way. Instead of writing whole
thing ourselves, which I'll show how-to in future, we'll do that using
awesome Chipsec framework. This way we don't have to care about
memory management, as we can just use python :).
Later on we'll be adding fancy payloads etc. but for now, we only want to
talk to SMI handler & hopefully break it in ugly & slow way.
Basicly, what we'll do, is just two loops, one looping SMIs, other Register
values. SMIs go from 0 to 255, aka one byte, and reg value will be between
0 and 0xffffff. Very slow, very uneffective, but works.
#!/usr/local/bin/python2 import sys import time from chipsec import chipset from chipesc.hal.interrupts import Interrupts cset = chipset.cs() cset.init(None, None, True) interrupts = Interrupts(cs) for reg in range(0, 0xffffff): for i in range(0, 255): print("SMI: 0x%x" % i) print("Register: 0x%x" % reg) time.sleep(0.1) interrupts.send_SW_SMI(0, i, 0, reg, reg, reg, reg, reg, reg)
And there you go, a simple SMI fuzzer in python.
Next time, we'll write it in pure C, with no chipset driver being used.
Also most likely adding a bit more sophisticated fuzzing in it.