Yep, cool. So, hello everyone. Welcome to our talk and thank you for the introduction. And in this talk, we'll be talking about how we're exploring secure cryptocurrency wallet applications. So, my name is Pei-Yu Wang. Here's what with my colleague Ming-Jie He. We're security engineers at CertiK. So, CertiK is a blockchain security company. We provide a variety of security services such as smart contract audit, chain audit, and penetration testing. I'm personally responsible for internal security review for our own product, as well as the external pen test, focus on wallet, Explorer, Exchange, and Dapp. So, outside of client work, we also do security research on different applications in the blockchain space. And that's how we come up with this talk. We also do bug bounty huntings over the weekend when we have time. This is the first time we speak at Defcon Blockchain Village. Thank you so much for having us here. So, what is crypto wallet? I'm sure most people here know what crypto wallet is, but in case someone don't. So, crypto wallet is a device, a program, or a service that stores the private key and the public key. So, crypto currency is virtual, like a wallet cannot physically hold the coins. And when you want to do the transactions, the wallet applications will use your private key to sign the transaction and broadcast that to the blockchains. There are different forms of crypto wallets. There's software wallets and hardware wallets. In this talk, we'll be focused on web wallet and desktop wallets. We believe there's two core functionalities for crypto wallets. One is account management. It allows users to create accounts, import accounts, and the other one is make transactions. It sends and receives coins. And for certain protocols, it will have additional features, such as for Cosmos-based wallets. They will provide the stacking features, allow users to delete coins to validators, and claim rewards. And looking at different wallets, we also find some, I don't know how to call them, maybe call them fancy features. For example, you can view newsletters in a desktop wallet. You can add third-party plugins in a desktop wallet. You can create a coin giveaway on Twitter in a web wallet. And there's one desktop wallet, the backend server allows users to upload any type of files to the backend server with the API. And then there's a desktop wallet that uses the WebView to implement a browser in it, which is mind-blowing. I don't know why people would want to use their desktop wallet to be as a browser. So we look at 45 different wallets, and we kind put them into two categories. One is host wallet. Host wallet is that the server manages your private keys. If you want to use the wallet, you need to authenticate, log into the application, authenticate with the server, and the server returns you session tokens or JWT tokens. Those secrets will either be stored in cookies or local session storage. And so most of what I will look at are decentralized wallets, which means the user manages the private key, the store, the key store, and their passwords. And after users create an account or import an account, those things will be stored in local or session storage or in the JavaScript variables. So in the 45 wallets, 27 of them are web wallets and 18 of them are desktop wallets. We think the logo for those projects are really cool. So we collect them and put it here. So let's start with the web wallet. This is a typical interface for a web wallet. This is our 30-bit wallet for 30 chains. In this interface, you can check your balance. It has the UI for sending tokens. And this is because it's a cost-based chain. It has the staking feature as well. So when we talk about web applications security, the thing that comes to my mind is OAuth's top 10. Here's some statistics on OAuth's top 10 in the 27 wallets we look at. We find Crystalscripting in three wallets. We'll do a case study for two of them. We find one SQL ingestion in a decentralized wallet. So the database only contains those transaction data. And because the transaction data in blockchain is already public, and we don't have a way to escalate that SQL ingestion to, say, command code executions. So that SQL ingestion is kind of just useless in this case. We found one broken authorization. An unauthorized user can mess around with other people's 2FA settings. But we cannot use this vulnerability to compromise a user account. A lot of web wallets are missing security headers. For example, CSP, the content security policy, and expert option headers, and make the wallet vulnerable to clear-checking. We see a few wallets using outdated JavaScript libraries, or outdated Nginx, Apache hosting, but we are not able to directly export them. So we have not seen any wallets dealing with XML, or find them doing any type of DCR audations. For the login and monitoring, we just don't know. So jumping to the first case study. So this is a DOM SSS in a decentralized web wallet. The wallet supports single protocols. It has all the basic functionalities for a wallet. It doesn't really have any fancy things there. So the vulnerable feature is the application saves the last location, the user visit, and it redirects the user to that page after the user unlocks his wallet with his password. In this URL, it will redirect the user to the valid data page after the user unlocks his wallet. And here's the co-implementations. The object return to equal to the parsing result of the window.location.search, and the return to variable pass into the window.location.href. If you have some experience about web app testing and stuff, you might realize this might be vulnerable to DOM SSS. And that is the case. So DOM SSS requires source and sync. So source is the location where untrusted data, the user input, is taken by the application and passed to the sync. So when user visits this URL, the window.location.search will return question mark, return to equal to slash validators. And the return to object will later becomes, will contain the streams slash validators. And here's the sync. Sync is the place where untrusted data coming from the source is actually getting executed. So the sync here is the window.location.href, and it's taking the user input inside the return to. So when it returns to slash validators, it goes to slash validator page. But if it's JavaScript, JavaScript, colon alert one, it's going to pop alert in the browser. So we have the DOM SSS here, but how can we export this to causing bigger damage? So this is a decentralized web wallet. The key store and the passwords are stored in the local storage after user creating account or import his account. So if you're not familiar with local storage or JavaScript, so JavaScript is able to read the content inside the local storage. In this example, there's a key value pair, hello world store in local storage. JavaScript can just do local storage.get item, hello, and we just get the contents. So now the attack plan is to steal the key store and password in the local storage with the DOM SSS. And that's exactly what this payload does. It reads the content of the key store and password and sends it to my web server. And in my SS log, I can see the key store contents and the passwords. And after I have those contents, I basically just own the account. I can use those information, log into the wallet and transfer all the money out. So for the fix here, the fix here is after user unlock his wallet, I just always redirect to the portfolio page. It just doesn't give the chance for attacker to inject any payloads here. So the second case study is reflect SSS in a host web wallet. So it has host web wallet. The server manage all the your private key. And to log into the applications, you will use your email and the one time passcode you receive in the email. The wallet supports 16 different coins. It has all the basic functionalities and one additional feature called Twitter giveaway. This is the API handling. So the API format is like the slash API slash endpoint. And the one to get user transaction is slash API users. And if you visit the non-existing endpoint, for example, slash API slash test, it will return the error message like this one. Translate to English, it's failed to resolve the request test. So what we're seeing here is the content in the URL is reflect bad in the response. And this is kind of signal that indicating that this if the backend doesn't do any standardizations or encoding, that might have the reflect scripting vulnerabilities. And that's exactly the case. So by putting slash SVG unload equal to alert document domains, the application just very happily popped the alert for me. And as I mentioned, this is a host web wallet. The private key is owned by the server. You cannot just directly steal them like the one in the first case study. So the plan here is to use these vulnerabilities to compromise either take over user's account or take over his sessions. So by looking around, I found that this session token is stored in the PHP SCSSID cookies. And what's special here is it does not have the that token does not have the HTTP only flag. So if you are not a website guy or web developer, HTTP only flag, if that has that flag set, it will stop JavaScript from accessing that cookies. In other words, you say it is it prevents attacker from stealing the session tokens in the cookies with the cross-site scripting attack. But in this case, there's no HTTP only. So I can just craft a payload that read the content with the cookie content and send to my web servers. So after I get the session tokens, I can use the session token, log in to the victim's account. So, you know, when you're going to compromise the wallet, the end goal will always try to steal the money. So I take over the session. Now it's time to take all the money. But wait, I can't because for the money transactions actions in that wallet, it requires a 2FA. So I kept looking around to see what I can do. I was not able to reset the 2FA. I was not able to disable the 2FA. But I found a feature. There's a feature called giveaway. How it works is you go into the interface, it asks you what kind of coin you want to give away, and how many of them you want to give away, and how many people you want to give it to. In this case, here in the screenshot, you can give away up to two bitcoins. I think that's a lot. And after you create a giveaway, what people will need to do is they need to follow you, text your friends, retweet. Once you have done that, you can go to the URL and claim the reward. And what's special about this feature is this feature doesn't require 2FA. So I can use the reflect-quota-scripting to steal users session tokens and use these features to create a bunch of giveaways and claim those rewards myself. And this way, I can just transfer all the money coins out from the bitcoins account. So on May 28, I reported these issues to the company by email. They act on these issues. And it was silenced for almost two months. And last month, their response to the issue is fixed and reward me $20 worth of coins. They don't really have a formal bug bounty program, so I'm fine with the $20. So the fix is the HTML encode output, so no more cross-site scripting. And they said HTTP only flag for the cookies that contains the session tokens. In this way, if the application is vulnerable to cross-site scripting later, then the attacker would not be able to directly steal the session tokens. So that's all about the case study on WebWallet. Let's go move on to DesktopWallet. So DesktopWallet is the desktop application as it's a wallet that runs on Windows, macOS, and sometimes Linux. So what kind of text that people use to build a DesktopWallet? So we look at 18 DesktopWallets. So one is Qt, C++, one is .NET, C Sharp, and one Java, and 15 Electrons. In the DesktopWallet case study, we'll first talk about a server-side RCE in a .NET DesktopWallet, and the second one is a client-side RCE in an Electron wallet. Now I'm going to mute myself and let my colleague Mingzhi walk you guys through the server-side RCE in the .NET DesktopWallet. Thanks, Pei. So hi, everyone. I'm Mingzhi. So I'm going to talk about a remote code execution vulnerability found in a DesktopWallet. So first, I'll give some background about the wallet. The wallet is a decentralized single protocol wallet. It is written in C Sharp, and it uses .NET framework. It contains many common wallet functionalities like account management, making transactions, and deploying and interacting with smart contracts. What's interesting is that it allows users to upload files to a server. This is not quite common in a wallet, so we decided to look into this feature more. As mentioned previously, this application uses .NET, so for .NET application, it is very easy to retrieve the source code by decompiling the executables if code obfuscation is not deployed. So this is exactly the case of the wallet, so we're able to recover the source code for further analysis. So after decompiling the executables, we found the source code that implements the file upload, as shown in the snippet. The wallet sends a HTTP post request to the server, and it returns with the file upload URL. So we saw file upload.php is the file that handles the file upload on the server side. So as a pen tester, this is very fascinating, as now we know that the server probably uses PHP as the backend. So if we could upload a PHP WebGL to the server and open it in a browser, we might get remote code execution on the server. So that's exactly what we did. So we are able to successfully upload the file using the wallet and access the file in the browser. So after clicking on the upload shell, we are able to gain a web shell on the server. We also discovered that the web server runs under the administrator user, so we are able to execute commands with administrator privilege. So at this point, we are able to gain full control of the server, and we are able to manipulate files uploaded by other users. However, as mentioned previously, since it's a decentralized wallet, the server does not store any user private keys. So you are not you cannot directly compromise user account by exploiting this vulnerability. So the fix is actually pretty simple. The developer just removes the file upload functionality in their further application so that they do not have to deal with it. This is actually a good idea, as the critical wallet is supposed to keep as simple as possible to avoid security issues. So now I will hand over to Pei Yu to talk about security in Electron Wallet. Yeah, thanks, Minji. So right now, let's jump to Electron. What is Electron and why Electron? Electron is an open source framework that allows developers to build cross-platform desktop applications with HTML, CSS, and JavaScript. Electron combines the core and render engine Node.js into a single runtime. So the benefit of using Electron is developers can reuse web application codes to build desktop applications. They don't need to have a separate codebase. They don't need to learn new languages. And debugging the Electron application is pretty easy with the Chrome dev tools. And Electron applications run on major OS. And because it can access to the Node.js modules, it can build a more powerful app compared to the web app in the browsers. So Electron security. So for most vulnerabilities that exist in a web app, you can basically find them in the Electron app. And for Electron's specific security issues, the Electron official security guidance provides very detailed information about what mistakes that people make that will make the application vulnerable and how to not make those mistakes. And in BlackHat USA 2017, a talk called a study of Electron security talked about advanced technique that you bypass the building Electron security protections to achieve core executions. But in this talk, we will be simply talking about one configuration called Node integration. So the definition for Node integration is it refers to the ability of assessing Node.js resources in the applications. So why Electron application can, although it's using web technology, but can build more powerful app than application running in the browser because it can import so many Node.js modules. But it does come with a greater security risk. So aside from the Electron official security doc is disabling Node.js integration help prevent cross-scripting from escalating to a so-called remote core execution RCE attack. So what does it really mean? So this is the latest version of the MyCrypto desktop wallet. In the configuration, it has the Node integration set to false, which has the Node.js disabled. And if you type require in the dev console, it will just say require is not defined. This is the early version of the MyCrypto desktop wallet. It has the Node integration set to choose and Node.js enabled. In the dev console, if you type require, it will show the require functions. So by copy pasting some malicious code into the dev consoles, this behavior causes cross-scripting. And this is what you will see if you open the dev console when you're in the Electron, in the desktop core application. It says if someone told you to copy paste something here, you have 11 out of 10 chance being scanned and you shouldn't do that. So normally in a web application, if victim exported by the self-SSS, attacker can probably compromise his account or do some damage to his account within the application. However, for Electron wallet, it might get from self-SSS to calculator. So to open a dev console in Electron application on macOS, it's option plus command plus I. And if you copy paste the following code into the console, you can see calculators. So if you're not familiar what calculator means, it's the way to show the successful of co-executions. So you see, I paste that into the console and the calculator pop up. So what if the victim... so if you want to use way to export a victim, the victim, you will probably will construct some really long weird things and ask the victim to paste into dev console and the victim be like, hey, I'm not going to paste this weird thing into my dev console. So how about this one? I'll paste this, it will allow you to claim one BTC. Just paste window location to href equal to HTTPS BTC giveaway dot sign. So by the way, that domain is available. It only cost $0.99 on GoDaddy. Yeah, so the victim is like, oh sure, this short command, I'm just going to paste into console, what will happen? So what happens, you're going to see the calculators again, because what the line is doing is it will redirect you to another page. And if that page has the malicious code, it will just go to SQL in your desktop wallet in the electronic locations. So here's a statistic on electron wallet we look at. So we look at 15 electron wallet that's in active development. So 11 out of 15 has Node.js enabled. This can either cause by they, in the configuration file, they set the node integration to choose or they use the electron version less than 5.0. So the electron framework later than 5.0, it has Node.js disabled by default for security reasons. And 5 out of 15 has Node.js enabled and have the dev console enabled. So it might just escalate self cross-site scripting to client-side co-execution. So this is one example that the attacker can trigger the co-execution directly without using self cross-site scripting. And that brings us to our last case study on client-side RCE on a simple desktop wallet. So the simple desktop wallet is an open source decentralized single-coin wallet. It's the application from where it's built. It's electron. It has all the functionalities, basic wallet functionality, and as an addition, future code view news. They have bug bounty programs on HackerOne. That's how I discovered them and start hacking the wallet. So since it's open source, I start with the code view. This is their, the build.js is their electron configuration file. What the here does is the process the platform is storing. It starts the application with the create Mac functions. Otherwise, it creates the start application with the create Windows functions. So, and in the create Windows functions, I see that node integration is set to choose. That means if the application is running on Windows, the node.js is enabled. So how can we export this? So my goal will be to inject arbitrary JavaScript. Self-cursor scripting? No, bug bounty program does not pay for self-cursor scripting. How about legitimate cursor scripting? No, I was not able to find one. But how about node untrusted remote content into the application? So, all right, let's do some news. So in the simple desktop wallet, it provides the view news features. And when you click that link into in the news, it actually read the redirect out the wallet and go to another website. In this case, it just opened up GitHub on inside the desktop wallet. So the exportation plan is I will host the webpage with malicious JavaScript. I will place the URL then point to my malicious page on GitHub. It can be a GitHub issues on the repo. I can create a repo and put it in the README. Or I can put it on my GitHub profile and then visit that URL in the desktop applications. This is a very easy, simple proof-of-concept code. What it does is there's a button. And when the button is clicked, it triggers the RCE count functions. What a function does, it just pops the calculators. And here's a proof-of-concept video. So I opened up the desktop wallet. I unlock wallet with my password. And I go ahead and verify the version. It's a very early version. This is the version back in April, I think. And I click the link in the news. I'm now on GitHub. And in this case, you ask the victim to go to certain GitHub page with a phishing attack. But for the demonstration, I just go to my personal GitHub account. And I have the URL hosted on my profile. And I click that. I go to the page that contains my POC. And I click the close. Calculator just pop up. So in this example, the POC script requires user to click a button. But in reality, attacker can just execute those malicious code automatically. And of course, attacker can use JavaScript to steal the key stores, steal the passwords, or it can, you know, use have like creating a reversal and control the victim's computers. So timeline must submit these reports on HackerOne. They triage and give me 2,500 bounties. And they fix in the next release. The simple team and the name team are really nice. I really appreciate they allow me to talk about this being public. So and the fix was they set the no integration to false in the build.js file and update the build news feature. So right now, if you click the link in the news, it will open up in the external browser instead of inside the desktop wallet. So again, I want to thank the team and they really value the security they use. Yeah, really fixed. So the takeaway here is attacker can compromise the victim's wallet or even the computer. And have you had a security audit before you allow users to have an internal security team? Definitely ask the security team for a security review. And if you don't have the internal security team, you have to hire a security professional for a security review. If you have any questions, comments, you can post it on the text channel or email us after you're welcome to follow us on our Twitter. This slide will be posted on my Twitter account. And you can, if you're interested, you can check out our company blog post. There's a lot of interesting blog posts that we talk about some hacks that happened recently or some technical articles. Thanks. Yeah, if you have any questions, just drop in the channel.