← All talks

The Dark Side of DeFi

BSides Ahmedabad · 202241:321.1K viewsPublished 2023-02Watch on YouTube ↗
Speakers
Tags
About this talk
Rudra Singh and Arbaz Hussain explore security vulnerabilities in decentralized finance and smart contracts, comparing Web2 and Web3 architectures, and examining common attack vectors including re-entrancy, griefing, and price oracle manipulation on blockchains like Ethereum.
Show original YouTube description
Rudra Singh (@0xrudrapratap) and Arbaz Hussain (@arbazkiraak) presented a technical talk on "The Dark Side of DeFi" at BSides Ahmedabad 2022 Slides link: https://docs.google.com/presentation/d/1i1Ski5EcxPczvjdlYAwwditmQFdLAeGEVC59h4Gkx20/mobilepresent?slide=id.g149676658b2_0_1169
Show transcript [en]

our next talk is definitely going to bring some uh okay our next stop is on the latest Hot Topic in the cyber world the web 3 security the Dark Side of defy how to spot potential vulnerabilities which will be presented by the immunified triages rudra Singh and urban please put your hands together for rudra and arbaaz [Applause] so hey everyone it's very excited to be here and today we will be presenting on Dark Side of D5 we're going to explore some of the potential security vulnerabilities we have in decentralized finance related to Smart contracts and decentralized web applications in general so who are we I'm our boss and I'm here with my colleague rudra Pratap and we

both work as a smart contact we are just at immunify and we are very much interested in investigating this ethereum virtual machine based decentralized Finance hacks and previously we have worked as an abstract engineer in web 2 industry and at the same time we also create educational content like we create Community challenges based on the common vulnerability patterns which is available at the GitHub and we also post about the common uh postmortems we have bug Fix reviews of of the bugs on medium at humanify medium so agenda of the talk is uh we're going to explore what are the smart contracts and decentralized Finance in general then we're going to compare this web 2 and web3 architecture flow like how they

differ from each other we're going to look into the common uh decentralized application vulnerabilities related to the web then going to look the most common smart contract vulnerabilities and auto we have this slide where we have collected some code resources to get you started with smart contact hacking so what are the smart contracts so smart contacts are basically they are just regular program code and they contain sets of inter instructions and conditions that needs to be executed the only difference the smart context has is they are immutable so what what what what it is mean by immutable is once they are deployed on a decentralized network like blockchain the state can't be modified so they are immutable in

nature and they are they are deployed on multiple uh different blockchains such as there is ethereum uh Solana and polka dot like many of you are familiar with different blockchains and they are very widely written in very high level languages like solidity which is very much inspired from JavaScript syntax then we have this wiper which is an another language in which this code is written which is highly inspired from python syntax then we have this classic rust and a stack based programming language which communicates with virtual machine so all these languages contains a set of op codes which is operational codes which helps in communicating with ethereum virtual machine to store read and execute instructions

so we're going to take we're going to now do a very basic architecture uh comparison between the web 2 and web3 so in web 2 like if a user have to access a web application uh he goes to the browser he enters the application name and the front end tries to communicate with the back end and the back end try to fetches the information from the database and the database renders the information directly at the front end level so this is the general webto architecture flow but things are slightly different when it comes to web3 architecture flow so in case of web3 when you go and enter a decentralized application URL the browser loads try to

load the application and the front end directly try to communicate with the smart contracts which are deployed on blockchain so browsers does not have uh ability to directly communicate uh with the smart contracts or a blockchain so they use a middleman here and the middlemans are the wallets which basically helps in communicating transferring out the information from the blockchain to the front end so this is the general architecture workflow difference between web 2 and web3 now like many of many of you guys have seen uh might have seen these meta marks or a wallet connect like wallets but what they are basically so what wallets helps you create a digital Identity On A blockchain so what

I mean by digital identity is uh they create your own account on a blockchain and using that icon like you can store the digital assets like ethereum it could be like any usdt token or erc7 like nft assets and all and whenever you create a wallet it creates a two pair of keys the first one is the private key and the second one is the public key so private key basically act as act as your master key it because it gives you an access to the wallet so using the private key you can access to your wallet your digital identity and there is a second which is public key which basically represents your address so if I need to send you some ether if

or if I need to communicate with you you must share your public key with me so it's basically represents your identity address and wallets as we have discussed in our previous slides they handles all the communication between the smart contracts and a front-end like read write execute uh functions on a smart contract which is deployed on a blockchain so now we are going to do an basic authentication comparison with a web 2 and how it differs with the web3 so in web 2 uh we used to have like in order to authenticate either we need to provide a email or a password or we we might need to use some auth providers like Google Google Identity or Facebook

identity like login with Facebook login with Google but in web3 like the authentication happens based on the signatures like in the GIF you can see there is a login with metabox button when you click on it it generates a message and once you sign that message you are basically logged in as uh you're basically authenticated and the whole process happens in the back background is based on the signatures so why signatures so and what are the signatures so signatures are basically 65 bytes long hexadecimal string and it is produced with your wallet so why signatures because as we have previously discussed that when you create a wallet it generates you two pair of keys that

is private key and a public key and you can't use private key to login as in login into the application because due to the sensitivity in nature and it gives you an access to your account so signatures are basically produced with the wallets and they are mean to be public and the whole purpose of the signatures is to prove prove the ownership of an account so if I say that if I own that particular address then I can prove I can produce a signature and I can give it to you and you can just verify if the signature belongs to me or not so one of the use case of the signatures was to do an offline gasless transfer so

whenever you wanted to do a transaction on ethereum like whenever you wanted to send out some tokens to some other user you must pay a gas fees but using this signature it it solves that problem because you can just create an offline signature and you can pass that signature to some other user and he can use that signature to just do an or transfer behalf of you because you just verified the signature so now we have seen that JF in the last slide where authentication happens so let's look at the workflow behind the workflow so whenever user initiates a login so whenever user initiates the login it sends the request to the backend and it

asks the backend to generate a random nonce and once the backend generates the random launch the user that message is get combined with the nonce and the user signs that message and once a user signs that message with the wallet it it produces the signature and signature is sent back to the back end and back end uh uses that signature and try to recover the address from the signature and validates if if that particular user is actually the owner of the owner of that address and once it validates it generates you the odd token like our token can be like JWT token and once you have this odd token you can you are fully authenticated and the last

thing the back end does is a cleanup process which basically making sure to expire the nonce which we use so that each nons each unique nouns is produced for each login iteration so here's an example of auth workflow so we have this is a simple HTTP request which makes uh post based request to generate JWT endpoint and it has three post data values the first one is the address which is your public digital identity address and second one is the 65 bytes long signature which was you just produced by signing the message you have that I am signing my one-time nonce 2619 you signed that message and it produced that signature and the request goes to that endpoint and the end point

try to validate if the signature is the uh is the correct one and once it verifies it generates you the JWT or token so now we're going to look at this common authentication vulnerabilities which will be discussed by withdraw so we can take hi everyone so we in the further slides we'll discuss about what are nouns and signature replay attacks and later on we'll learn about a common misconfiguration in dapps which can lead to authentication bypass missing random nons ah so the question would be like what is nons is nothing but a random unique value which is generally used as a separator to create a unique signature so whenever you request it is it's it helps us to create

a unique signature and these signatures are generally meant to be used once so if an application is failing to invalidate the signature then there are chances that the application might be vulnerable to Signature replay attacks so in the given figure you can see that there is an endpoint called generate JWT so it takes three component mainly which is address which is the address of the signer who is signing the message the signature the signature is uh nothing but uh the message hashed with the what like the the public key of the signer and the message is the message itself so as you can see I have highlighted that the message value does not have any unique

element to it which like which is nons of course so there is no non so whenever we try to create uh the signature out of this message then the resulting signature would be the same it is because there is no unique element attached to it so the resulting signature would be the same as there is nothing unique to it so it's recommended that we add a random nodes so that we the signature cannot be replayed moving forward validator arbitrary accepts any message so as I said we'll take an example of the same so an application is said to be vulnerable to these kinds of attack if the back end of the application is failing to validate whether the user

provided a message and the signature is something that the application asks for so it's not that we are like arbitrary providing some gibberish in the message or the signature so let's understand it further within the help of an example so I'm not sure whether you are able to see the figure or not so it's of etherscan which have this huge data set of public verified signatures and as arbas mentioned that signatures are meant to be public it's not sensitive in nature so if you have noticed that the uh that there are this is one of the entries of the database and it consists of address sign message and signature which is the same required by the

application and generally for authentication in web 3 these are the only three components limit like generally there are more component but mainly these three components are used for authentication purposes and what if we just replace an arbitrary like random entry from ethereum database with the our endpoint that then that will generate a JWT based on the three components so when we send it to the server the server just generally takes the signature and try to recover the public address out of it and in this case it would be the the address of the signer that we took from the entry itself because it's it's a valid signature at the end of the day right then there is like there are chances

that we can generate JWT token of an arbitrary entry from ethereum database so how can we prevent it so generally applications need to verify that the signature provided Us by the the end user and the message itself is something that the application asks for so we are not arbitrary providing any random gibberish client-side injections so as you know that access is not unique web 2 has xss but it it'll go like P2 P3 or something like that but in web 3 the Case is totally different we consider as P1 critical and but the question would be why why we do we consider because as you may know that there is there are extensions uh installed in uh browser

which are namely metamask so it when we try to visit any depth they inject their their own native code so that they we can interact with the application and the metamask extension so injecting any arbitrary JavaScript JavaScript code on an application would allow us to initiate a false or a fake transaction on on in the origin of the website that we have injected so it allows us to create or initiate malicious transaction so the same case happens with Badger down which ah allowed the hacker to steal over as it's worth over 120 million so what was this the incident was the hackers was able to find out zero day in cloudflare which allowed him to inject arbitrary code JavaScript code

on the client side of badger down and so the hacker did nothing but they replaced the client-side code that would initiate transaction from the user wallet to the attacker wallet leading to the loss of 120 million out of us so we have just seen the common decentralized application authenticated vulnerabilities now we're going to jump dive into decentralized finance and common smart contract vulnerabilities so decentralized Finance so it's the same uh it has the same concept like the traditional Financial ecosystem but it was created using the blockchain technology so users can buy sell assets and perform exchanges and like borrow take out the loan on a decentralized finance but the only difference is uh they are not centralized and there is no

middleman in it so some of the examples is decentralized exchange which basically allows anyone to come and trade uh exchange like exchange swaps like you don't have to provide go and create an account like you don't have to do any kind of kyc so that's the like plus point they offer and there is like borrow borrowing lending platform where users can come and Supply some asset X as collateral and can borrow y asset and yield farming protocols like whenever you have some tokens lying idle in your wallet you you can just invest into yield farming protocols and generate and fix interest on it like similar to the traditional Finance we have then we have this

derivatives which is basically related to the Futures calls and options so it has all the same Concepts it was all produced on using a blockchain technology or in a decentralized way now ah let us look at the common smart contract vulnerabilities so we have three cases which is very common or commonly spotted vulnerabilities the first one is unsafe external calls so what are the risks Associated when you force and contract to make an external call to some untrusted contract what could go wrong then secondly we have this griefing vulnerability where uh Griffin basically means the attacker has no profit motive he does it like to go create a disruptions of service like denial of service like dos and the

second and the last one we have this insecure external dependency like what could go wrong if in smart contacts are relying on some output value of in third party contract and doing something with that value we're going to explore one by one case so first let's understand what are these external calls so external calls are basically every smart contract communicates with another one by making an external calls but here here are the some rigs associated with it like when you force and contract to make end call to some untrusted and third party contact like what could go wrong as smart contract could be not it's not in a state where it could handle such uh

outcome reaction of the Callback so we're going to explore what are the rigs in the next slides so basically there are two types of external calls the smart contract makes the first one is the static call and the second one is the delegate call so the both they both allow us to call some other function of an contract the only difference is the static calls allows you to transfer out the ether as a balance to some other contract so let's understand the first vulnerability which is a common uh you commonly found which is a re-entrancy vulnerability and it's been done with a call method so re-entrancy occurs so when a function makes an external call

to some untrusted uh third party contract and you use the third party on contract to make a recursive call back to the original caller contract so you are just making uh the Callback to the from where the incoming call has come and it it does to steal funds or do some malicious activities so we're going to explore one with this example but first who can be the callers so there are only two callers who can call actually call to the smart contract the first one is the eoa which is us who are not smart contracts and the second one is smart contracts itself so smart contract can call other smart contracts so let's understand with a small snippet

about this attack Vector so there is a withdrawal balance function and the first thing it does is uh when you call this withdrawal balance function it try to retrieves your user balances like message dot sender is the one who is calling that function so it it try to try to fetches the amount of balance you are holding and it try to store that balance into amount to withdraw variable and on the next line you can see message dot sender dot call so it's making a call method to whoever calling this function and basically it's saying to transfer out the funds like whatever the funds we just save in amount to withdraw variable and third condition we are just checking

if the transfer was success or not if it not then just it will the function will reward and the lastly we are updating the state where we are updating the balance so we are just keeping user balances message dot sender to zero so firstly we are trying to retrieve balance then we are transferring out the balance then we are just setting the balance to zero so what could go wrong into it so let's say there is a simple exploit contract which has this uh receiving incoming call function where we are just checking if the call coming from the vulnerable contract then again try to call back to withdrawal balance function so what happens here is uh when

when message dot sender dot call uh it will basically try to cause this function and and this function will again execute this withdraw balance function so the whole vulnerability here is the amount to withdraw variable we we just try to fetch is the fetches the balance and it's stored into that balance and it try to send that balance but at the line at the last line we are just updating the balance so it will assume that uh the the user has the same balance so it keeps sending the balance again and again again and again until it end and until the whole contract is drained out so how to fix this vulnerability like you can able to like re-enter into the

same function so there are two popular ways the projects have been doing the first one is the mutex Locking this is the same concept like thread processes use so that they don't modify the each other state so they just lock lock the state so that another process cannot access that state and the second one is checks effect interaction pattern this is in popular pattern which many experienced developers follow so in this pattern the first condition is we need to perform checks then we need to perform effects then we need to do lastly interaction or any kind of interaction to external contract so let's ah see this pattern into more detail so here's the comparison with

vulnerable pattern and the checks effect interaction pattern so you can spot that in the vulnerable pattern we are doing interaction first then we are updating the state at the last setting the balance to zero after transferring out the balance but checks effect interaction pattern first try to fetches your balance it stores into amount to withdraw variable then it updates your balance to zero then it does an interaction to the third party contract so that users even if they try to re-enter their balance is already set to zero say so they they can't withdraw more than once now let's look at another call method delegate call and let's understand this delicate call with an example so the

call and delegate call they both use or to call some other function of an another contract the only difference with the delegate call is let's Suppose there is uh contract a and a contract B and contract a is making a delicate call to contract B so contract B has this set num 5 function and when counter game makes a delegate call to contract P it executes that set num 5 function in a contract B but but the storage happens at the contract a so if we look at the memory slot uh like if you look at the contract s slots it end up updating the storing the value of Phi in contract a not a contract B so it's

just executing the logic of contract B while updating the state of contract a so that's the only difference it has and using this method like contract a can preserve States like it can use any logic but the storage will keep getting updated so it can it can be used this method can be used for previous preserving the storage and this whole whole delegate concept uh introduced the concept of proxies so smart contracts has this proxies contract which we are going to explore now so the proxy basically the whole functionality of the proxy contract is uh is it is used to just storage and whenever you make a call to proxy contact it delicate call it just

forwards your delegate call to the logic contract and the Logic contact basically executes your logic and all the state changes happens and the balance update happens at the proxy contract not at the logic contract so there are two types of proxies uh the first one like they are the popular one the first one is transparent proxy pattern and the second one is universal upgradable proxy standard the only difference is you can upgrade the logic contract like whom you should forward the call you can upgrade the logic from the proxy itself and the second one is you can upgrade the logic contract from the Logic contact itself and there is a popular vulnerability associated with this proxies uh that is

like very simple to find and it's related to uninitialized proxy bugs so every contract uh every contract which is related to proxy has this initialize function which is basically saying like once you once your contact is deployed you wanted to set some things like some variables some Access Control roles or whatever so initialize function has has ability to do it and you that is function is only callable once so once you call that function you can't call again so that's the use case of this initialize function and a lot of times it's not a problem like keeping uh initial keeping initialize a function public it's not a problem because they don't contain much much problematic but

problem will occur when they have this logic where when you call this initialize and whoever calling the initialize it will make the it will grant a ownership do that and once you become the owner like once you become the owner you can upgrade the contract itself so that's very harmful and like once we get once a user get the upgradability he can just destroy the contract itself or he could drive the contract into some some unstable state which could make the proxy contract useless so let's understand this whole concept with a diagram so there are there are these users uh who is who are calling to this proxy contract and the proxy contract just making a delegate call to logic contract

so it's just forwarding all the calls to the logic contract and whatever the executions happens in the logic contract it updates the state in the proxy contract so this is the normal workflow now let's Suppose there is a malicious hacker who just found a way where he can use the logic contract to make an external delegate call to some malicious contract which he deployed and that malicious evil contract contains a special evm op code which said which which is self-destruct which is basically saying to destroyed destroyed itself like whoever called call that op code it will destroy the contract on the blockchain so he called he forced the Logic contact to call the evil contract he which he

deployed and it executes Logic contact executed as instruction and all the state changes happens in the logic contract not in the evil contract so now uh when users try to call the proxy contract the proxy tried trying to forward all the calls to the logic contract but it is destroyed already it's not since the attacker already forwarded the call to self-destruct and it's deployed so the proxy becomes useless as a storage encode or erase from the blockchain so there is a popular bug which was found in Wormhole it's related to the same so there is initialize function uh where when you call the initialize there is a ownable init condition like which basically means you

make the caller as the owner like whoever call this function it makes the owner and once you become the owner you can authorize upgrade your logic contract so the white hat found the bug in a warm all where there were like 1.8 billions of assets were residing and he can hold the entire contract for a ransom and he reported through immunify and he got a bounty of 10 million for for his uh findings and we also created a POC uh for reproducing these all these bug in a local environment so do check check out that POC now coming up the next vulnerability pattern which is push versus pull pattern which is very commonly found so

we'll be discussed by rudra

pattern so generally this class of vulnerability happens when a smart contrast smart contract is trying to send ethers to a user which could be us or a smart contract so the result of this the exploitation of this class would lead to griefing so griefing is nothing just basically in layman's term you can say that we are just destroying the logic or the making the smart contract unable to be usable by other users so let's discuss with the help of an example let's Suppose there is an nft auction workflow so the uh the workflow of the nft auction works like as follows so there is a smart contract called nft auctions which is residing in blockchain

so it's user one is making a bid of let's say suppose nft for NF nft and he's bidding 100 dollar for the nft itself but at the same time user B uh overruns him and he or she makes a bit of 200 dollars and let's uh like smart contractable thing he the 200 is much bigger than 100 so let's return the money back to user one because uh he just lost the bid so this is the general overflow the smart contract is returning the money that the user once entered the initial stage and refunding it so so this logic looks like something like the snippet that we have shared and you can find it on our uh Community

challenge GitHub so the course is nothing but it's just saying that if you lost the bet just the smart contract will return the money that it is owned by the smart contract so how can we exploit it so let's suppose we deployed a evil contract and we are making a bid of 100 and at the same time someone outruns us and when while while returning the money we just break the logic how ah we will We implemented a fallback function in our smart contract which just says that if someone sends me the money I won't accept it just return or just reject the money so we are creating we are destroying the logic of the contract so

when when the nft options try to refund the money we are just saying we won't accept it and just rewards so making it making the nft contract unusable because it won't process the transaction and it won't move further so nft that the user to one would get lost it it's just stuck in the smart contract and it's not unable for anyone to use further so the fix for the same would be like using the pull method so that major differentiation between the both is that instead of sending the transaction at the same logic instead the user one request for the refund so we have created another function so it just says that give me my money back and that's it

like it's a simple explanation to pull

so the third and most common vulnerability case uh we see in a D5 is a spot price dependency like we're going to explore what more in the spot price like I we already mentioned that in order to determine some price of an asset like any any token and all the smart context must rely on some source of information and what could go wrong if that source of information could be manipulated or could return a very stale data so uh price oracles let's fund let's find understand the price oracles before we jump into the spot price so price oracles are the smart contracts which basically determines the value of an asset like if if I wanted to identify

the value of Solana token I can go to Oracle and I can just it will it will just let me know like how much it will cost me to buy and Solana token and like in order to develop such uh like price identifying uh price identifying contracts like we can't really rely on like apis like if I have to develop an application in a web 2 I can just go and rely on some API endpoints of like coinbase some very good sources of like coin market cap conteco but things are very different when it comes to blockchain like you can't integrate an API you have to always rely on on the blockchain data like on-chain data like uh decentralized

exchanges which are on blockchain like uni soap and a balancer and in the next slide we're going to see how the spot price calculation happens uh in a blockchain so let's say I wanted to buy a one Bitcoin and I'm holding ethereum so I can just go to this uni swap or decentralized exchange and I can look into the ETS and Bitcoin pool and the way it calculated calculates that how much ethereum it will cost for me to buy one Bitcoin is basically by grabbing The Reserve balance and dividing by them too so let's say the pool has 20 Bitcoins and ah and the another asset is it has a 100 ethereum so we just divide y by X which is 100

divided by 20 and it it says that to buy a one Bitcoin it will cost me like five ethereum so now uh like one thing we can understand from this is how the price how much it would require for me to buy is how much is uh dependent on the amount of tokens residing in that pool like the amount of reserves so it's really easy to move the price based on making buying and selling pressure so mainly the attackers take take out lot of loans and manipulate these reserves and whoever relying on these reserves they will go and exploit there so we're going to take we're going to take a we're going to uh in the next

slide we have I have a figure where we're going to explore how this vulnerability can be exploited on a boring platform so this is a normal borrowing lending platform where user have to deposit some X assets as a collateral and they can borrow y assets and they can just pay interest of borrowing asset and can get back the original collateral which they supplied so there is a user which has one ethereum and he goes to the protocol which is a vault protocol and he says I'm going to deposit one ethereum and I wanted to borrow like uh 900 usdt or like give me all the usdt of whatever I am depositing so now the Vault what it tries to do it

tries to find the value of asset value of asset you just deposit like you deposit one ethereum so try to find the price of one ethereum you just deposited so when it queries the price of one ethereum it goes to the uni swap the same pool which in the previous slide we discussed how price was calculated and that pool will return the price is thousand dollars and the world now says yes the value of your deposited collateral is thousand dollars so you can borrow up to 900 that's your limit because all the loans are under collaterals so now let's look at another case where attacker simply has like ten thousand dollars and he can directly go to the

Oracle pool of unisop and he can just swap he can just sell his 10 000 uh dollar of us data and he can just try to buy all the like majority of ethereum from that pool so what happens when you make a large transaction like this it will push the price of ethereum like it inflates the price of ethereum in the decentralized exchange and once the price is inflated the attacker can sub can supply the eight ethereum which he got from the first transaction and he can supply that eight ethereum to the Vault and the now Vault try to query the price like world again goes to the Oracle and say like can you determine

the price of assets the attacker is depositing and the now the Oracle Returns the ten thousand dollar which basically in the inflated price the last traded price of the of the Oracle and the world says that you just supplied the eight ethereum uh like you can borrow up to 72k worth of usdt so the attacker just Ricks 10K usdt to manipulate the pool and he borrowed 72k so it's like 62k profit for an attacker he can just run away by manipulating and exploiting the world so this is a very uh common box we see around in D5 where Oracle manipulation happens and someone goes and exploit the walls and runs away yep so what are the solutions to the

spot price the many protocols follows on time weighted average price they follow so instead of depending on the last traded price they have this time ranges like 30 minutes 60 Minutes interval and they just averages all the fluctuations happens between so they follow one and the second one of the method they do is instead of just relying on One Source they rely on multiple sources so they just combine all the other decentralized exchanges and they just combine up and they get an average price so that's the way they do and that's it like that's all the common vulnerabilities we have discussed about the decentralized applications and about the smart contracts so in this slide we have collected some

useful resources to get you started with blockchain hacking and yep that's it [Applause] so due to the time limit uh I call because not able to do QA so we will be around so if you guys have any questions feel free to reach orders thank you

thank you like definitely web3 is so attractive as you people mentioned like every bug is P1 and who doesn't want that money thank you so much again for sharing all the knowledge with us