Auditing zkEVM and it's attack surfaces
ETHCC 6 · July 2023 · 16:24
Vahe Karapetyan shares lessons from auditing Polygon's zkEVM. The speaker discusses attack surfaces, security-review reasoning and selected audit findings.
Speakers
Topics
From ETHCC 6, hosted by Ethereum France.
Transcript
[Music] foreign [Music] so uh hey everyone today we'll be talking about auditing ZK VM overviewing its attack surfaces and showcasing some of the findings we had on polygon ZK VM audit I think the main purpose of the talk will be to compete for most boring talk on this CC so yeah let's try win that so my name is vaheim some people know me by my nickname Cameo I've been doing cyber security for around a decade doing web and binary exploitation before that
I like I really like playing ctfs you can tell it by my t-shirt and I'm co-founder at hexins we do all the cool stuff blockchain audits cryptography ZK of course and we also develop security products so uh ZK VM is growing crazy a lot of great projects developing ZK VMS like polygons Scrolls UK sync Taiko uh well the high level overview just in a couple of words like ckvm takes as input the old L2 State and some transactions and outputs like the new L2 State and generates the proof that you can use on the layer one
to change the state so today we'll be more talking about the polygon as we did the audit uh it's it's a huge code base it has around 40 components but our main focus today will be the prover uh as of the heart of the ZK AVM so uh polygon had this uh interesting approach of mimicking microprocessor and like having a hardware uh layer and then an assembly language that works on it and on top of that you have a ROM basically zkvm written uh in the cksm level so the hardware is called pil it's a domain specific language for defining State machines with its registers as polynomials that's basically like the
constrained main constrained part of the uh of the ZK AVM and like generally speaking the pil can be used not only for the ZK AVM you can just write your own State machines and have them provable so yeah on top of that you have the ZK SM that works with the hardware and using this ZK SM you just emulate the evm and you automatically get the zkvm so what kind of bug types are we looking at in terms of ckvm audits so of course it's mainly the soundness and completeness issues so sound like soundness is basically uh that you cannot prove any incorrect statement and
completeness will be that any correct statement should be be able to be proven so in terms of like applied security Auditors are more likely to look at soundness issues because that's the ones that bring you like to a bigger impact like proving that you have much more ethereum balance that you have actually and completeness is more like mostly like the denial of service attacks so there are lots of layers where you can find this box actually the short answer is everywhere you gotta look everywhere like it might be discrepancies between all the layers but the ones worth noting definitely is the circuit design so
whether you have implemented all the constraints that your program assumed uh another one is if you're doing ckvm you'll be implementing or deriving a lot of cryptographic Primitives and it's very easy to break something there we can see a lot of weak feature Transformations reported before that like the description discrepancies from papers and Etc so another very important part is the program logic vulnerability so basically the whatever you're proving it should be it should be working right and it can have like logic vulnerabilities uh and of course unintended discrepancies
between EVMS and zkavms let's not forget about the rest of type of attacks that are not directly connected to ZK bets do you still have them as you have some con smart contracts you can have some vulnerabilities there some misalignments in economics or you still have notes some attack on nodes so today I'll be talking about a couple of bugs on different layers so the one is on program logic layer and the next and the second one is on the constraint level or rather but I will not be too technical on them as we're quite limited on time but you can uh scan the QR get the full audit report and take a look at the details there so the first one is the memory
management bug that we found so basically how ZK VM handles the dynamic memory in in evm so we have stack you have dynamic memory although m-store M load happens and for ZK VM uh it's also following this microprocessor logic and it has one physical memory and for him all this context-based stacks and dynamic memories are like virtual memory and just map with a certain formula to a real address like physical addresses right one important thing about this context so every message has its context so when you create an external call it creates a new context so you don't overlap the
memory and one important thing here is that context also includes the global and local variables so not only stack and dynamic memory but also that and the pil uses a special register called context CTX to be sure that you do not overlap there but eventually we managed to find a bug in the identity pre-compile implementation whereas through a specifically crafted transaction when you call this pre-compile you can actually corrupt the CTX to get the value zero and the most interesting part here is that CTX with value 0 is a special context you cannot get like ctx0 if you're executing the transactions or
making calls like the main difference is that for the for the context zero sorry for the context 0 instead of local variables you store them the global variables the global for the ZK VM like old stagewood or old account input hash and other stuff and on the other hand like if we will be in the in the message we'll have like gas limit destination address and that kind of stuff so actually corrupting the C takes to zero we have a very interesting thing here is that we uh we have a double reference between this value so for example in ZK VM when we when we will be querying gas limit
we'll be actually getting the Old State Route right so uh for you that versus Sim uh had some experience with binary exploitation it's like classic double reference bug but let's see like how we can leverage this bug to actually let's say make some money eventually we found the function in in ZK VM called handle guest as basically a function that credits sequencer for the transaction fee basically just multiplying guess price by gas limits and crediting it to the sequencer balance and as you can see like the gas limit here will be the Old Stage route which is a hash value and it's almost
guaranteed always to have like super big absolute value in it and an important part part here oh yeah an important part here is that we have an assertion of this multiplication not to overflow so we need to put the gas limit equal to one and at that time like the gas price uh the gas price equal to one and the gas limit will be all state route and will be credited like enormous amount of ether to sequencer but right now there's only trusted sequencer uh but yeah further on polygon is going to have like decentralized sequencers
so the next one will be on the constraint level uh the zksm has an interesting cop guard it's called jump negative jump in as you can see on the right side uh so when the result of the operation is negative it jumps to the label mentioned and you might not fall really into this formulas but the thing is that how pil handles this it has us it has a selector called is negative and uh when the result is not negative is zero when the result is negative it's one and this is negative polynomial eventually flows down into the last formula of uh the next extraction constraint like program count
ZK program counter as you can see but the thing is that we were missing a constraint here that is negative is should have binary values 0 1 but we don't have this you can see the constraint you don't have that constraint there so using this we actually can leverage a very interesting thing uh wherever our result is negative we can using like very easy for derived formula for how to put the is negative and operation values we can jump to any label and not just the label mentioned here like fail assert we can jump to any line in the firmware this is also quite
similar to to Binary bugs uh like we have a execution flow hijack and we gotta find now a gadget chain so where can we jump it so it continues the execution in a way that first we don't break it we don't break any assertion otherwise it would be unprovable and we don't need that that will be meaningless attack and the second one to get the like the most important impact like uh for the for the hacker attacker to have some arbitrary balance on that and eventually we found a jump chain that you can use it ends up with a refund gas function it goes to like delegate call the compute gas and refund
gas and eventually the refund gas uh it's is the function that refunds the caller the unused gas amount and we use these three lines that it sets the balance and using this first two calls that actually just the registers in a way that we need them to work there So eventually we can uh we can credit arbitrary amount of uh either to anyone using this so another important thing about analyzing this kind of projects is when you work with this kind of dsls or even like peel or even the zksm it's always really good
idea to have a static analysis because you have lots of polynomials you have lots of constraints and you really can improve your audit with automation but the deal was either novel language so we don't have a zest and eventually during the audit we write our own one we call it pillar and one of the and we had couple of really very interesting features in them the first one is the constraint templates you can write a template of constraints you want to find or to exclude them uh just you can you can see on the example you just write the pill like there is one polynomial a a multiplied one minus a equals zero and the template engine will find all the
constraints that look like this and also we taint all the committed polynomials so one nice example that we used and really found missing constraints like this so we parse the executor for polynomials that are actually signed only with zero and one values and then we use this template engine and uh polynomial painting to find the polynomials that don't have this kind of constraints and we found a couple of them so we've open sourced that but it's like a still like a play Tool so uh highly encouraging all of you just you can four contribute it will be nice uh so last but not least as we're really limited on the time so uh for all your
uh Security Experts or developers that like to contribute to web3 security we're launching our web3 security platform it has a knob domain like r.xyz where uh please go ahead and register of on a wait list because right now we'll be in a closed stage uh will be a lot of there'll be a lot of really dope uh features and tools that will help you find bugs uh one of the important ones I I like to mention is a couple of a couple of speeches ago it was mentioned that we see a lot of bugs repeating like the same kind of bug repeating itself over and over and over
so we'll be closing that issue we'll be addressing that issue with one of our tools and I think it will be great so yeah stay safe find bugs prevent hugs thank you yeah one two all right so we're going to have a small q a time for one or two questions hello thank you for the talk uh it seems like the findings that you have in this audit were very specific
uh is was there any uh any methodology that you followed was there any uh focus on specific types of invariant that you use during this audit can you elaborate a little bit on that yeah so I I believe that whenever you'll be auditing a ZK VM most likely your findings will be very specific to that dkvm implementation because whatever we talked about like the scroll the daiko the ZK seeing the polygon all have like different approaches different different architectures different Tech stack so now I would say that the main thing that you need to understand to go through uh like a ZK audit the first the first thing is to understand that it's not like execution-based program
it's rather constraint based program so you will not everything that you see that is written is actually checked and like working like you expected because you'll be a lot of you'll be having a lot of free input coming out of the executor and you need to check all this in constraints so that's that's a bit like a shift of mindset between auditing like a classic program let's say and uh ZK approval one any further questions nope Well yeah if you have any questions feel free to reach out to him and I think we can close it here
okay thank you thank you [Applause] [Music]