 Hello everybody, nice that you're here. My name is Eric, my day job is pentesting code auditing and I want to talk about the stuff I did in my spare time for like the last year. The issues I'm presenting are fixed. I have told the vendors about them. So no audits, there are some quirks about this, more about this later. Audit issues are an open source project, so if you're using them, help them finding such issues, read the code, this is not about blaming them, that they write the code, this is more like hey, help them. I have some stuff for proprietary smart card drivers as well, but I'm not really interested in debugging them in my spare time, so yeah, that's why I don't have bugs in them. I know they are there, but I didn't debug them. What I'm talking about, I'm talking about the tech computers with smart card, smart cards are used in a lot of different areas, you have your phones, you have ATM machines, you have cars, you have healthcare environments, I'm mostly interested in the Linux tokens, so when you're using a smart card as a second factor, this is a good idea or not. That's basically the question I was asking myself. Why would you do this? The smart cards are used for the authentication process. This at least on Linux runs as a route, so if you have a bug there, it's game over, and you have this interesting effect that the programmers who are writing software for smart cards always think of the smart card as this trustworthy, highly secure device, so they trust it, and this might not always be the idea. To have a first look at the smart card stack, you have the user which wants to lock in. The user is using a smart card for which there is a smart card driver, and you have a reader which also requires a smart, which requires a kind of driver. On the lower layer, you have the physical smart card, which is this highly secure, temp-approved device, contains the processor, some memory, and people were always focusing on the smart card when attacking the smart card security, and tried to glitch it, tried to decap it to read out the keys. I went the other way and looked at the software side. If you are talking to a smart card, you need some protocols. The lowest level is the APD use, which you are sending to smart cards. It's a very simple protocol, as you can see. You have few bytes, which define the kind of package you are sending. You have some parameters, P1 and P2, then there's a length, byte, and then you can append some additional data. If you look at the bottom, there's a small example. This is basically a command which sends a pin to the smart card to unlock the smart card. In this case, 1, 2, 3, 4. As you can see, it's very simple. The response is simple as well. You have your payload, and then two status bytes, which say, okay, this was successful or we have an error, or please request more data because there's more than I can fit in the response. On the top of that, you have the layer which controls the reader. The interface in this case is also quite simple. You give it a buffer length, and that's the data that's spent to the card, and you give it a buffer and the length, and that's the data you get back from the card. So it's quite easy. There are some additional API calls to control further settings, but this is the one which is relevant for me. The API is similar on Linux and on Windows, so you can easily port your drivers, and this is more standardized somewhere. On top of that, the next section layer is PKCS11, which is also platform-independent, which you can use, for example, via your browser to access the certificates which are stored on the card. So you have a common interface which is portable in everything. In this case, you have an API call which allows you to find objects on the card, for example, certificates or others. Windows by now has a different interface. It has the SmartCard MiniDrive interface, which basically is quite similar, but different. The thing that is interesting when loading those drivers, as soon as the SmartCard is plugged in, there's this answer to reset, which is basically a string of bytes which tells the reader or which test the operating system which driver it should load for this card. So these ITRs are specific to the card, and usually you cannot change them. So that means they are static. Yeah, this is a quick recap of the stack, and what we are taking is the APDU part, which is the SmartCard driver. What does the lock-in with the SmartCard look like? On the left you have the PAN, the Plugable Authentication Module, in the middle is the SmartCard, and on the right is the Certificate Vocation Server. First, the computer asks the SmartCards for all the certificates it has stored, then it picks one, validates it, if it's from the right CA, if the user makes any sense for the system, and if it's valid, the CRS server is asked if it's revoked, or if the certificate can be used for authentication. The check is, for example, done by using lip-curl or something, so if you're taking this, there's lip-curl running this route right there, so if you have interesting bugs there, that's the way to use them. The next step is to generate some random numbers, and these are sent to the card, and the card is expected to sign those random numbers to prove that it contains the key to the certificate. And after this is done, the server or the computer checks if the signature is correct, and if it is, it knows, okay, this is a legitimate card for this user. And, yeah, that's basically your lock-in process. So I already told you the SmartCard driver developers always trust the card. It's, I'm not sure, maybe some subconscious thing that they usually don't expect it to send something strange, or, and that's why I'm looking in and what I'm trying to use. Those are the projects I found, Buxin. Two of them are Ubico projects. The patching process with them worked quite fine. Then there are SmartCard services, which is the old Apple SmartCard stack. When I contacted them, I told them, hey, I send a talk to DefCon and want to talk about it. Let's coordinate the patching and the release and everything. They did not answer, and after, I went through three weeks, there was a reply, hey, we fixed everything and you're good. So, yeah, I asked for an embargo. It was kind of strange. They didn't even mention that it's like a security bug fix or everything. Then there's OpenSC. I worked really good with them. It's the classic Linux SmartCard driver stack. It contains drivers for a lot of different cards from a lot of different people. So, a lot of the tech service fuzzing, this was quite rewarding. There were tons of bugs, but this was also a project which was very good to work with, especially Frank Morgner did a good job of getting the team there together and trying to fix everything. The only problem is I also coordinated the release with them on like four days ago. But nothing happened. I'm not sure why. They didn't release anything. I haven't heard from them since then. So, we decided to publish the private repository where all the fixes went in today. So, you can install that in case you're affected and don't, yeah, you need to link it there with the known vulnerabilities in the software without having a patch. But I guess there will be a release in the next few days to address those. I did a lot of fuzzing on OpenSC, but it was sort of like huge cloud. I only fuzzed certain parts, so there are certainly more bugs in there to be found. So, if you have spare time, want to look at the stuff, go for it. What kind of bugs did I find? For the Apple SmartCard services, for one of the drivers, we have this code. It's a loop, and it waits or it loops until the card sends those responses. And if the results start with 6.3, it says, hey, you need to fetch more data. I have more data for you. And the loop until the card says, okay, or until the card no longer says that it has more data. And in each loop, they retrieve the data from the card and append it to a buffer. So, if the card never stops saying you fetched everything, they continue copying everything into the buffer and on and on and on until you have your classic, in this case, heap overflow. So, that's nothing you want to have. It's your classic memory corruption. For OpenSC, this is a bug in one of the helper tools, not in the main driver. There's a buffer of 2048 bytes, and they have a variable buff size. And they request a file from the card and or selected a file from the card and the selection process gives you a structure which, for example, contains the size of the card, the size of the file. So, what they are doing, they are using the size of the file as a parameter on how much data to request from the card into this fixed size buffer. So, yeah, as soon as the file is bigger than 2K, you have your classic buffer overflow there. And it was told you should always bring like a calculator if you're talking about buffer overflows. Yeah, what the tool does is you can use it to read, for example, the search from the card. That's the minus R parameter which triggers the code I showed you. And yeah, using the buffer overflow, you can spoil whatever you want in this case, the calculator. How do I exploit this? As I said, these RTLs which define which driver gets loaded for a card are usually static. You can't change them. I'm using a basic card which is a smart card you can fully control and fully program in basic. Yeah, it's 2018, but it's basic. And for these cards, you can change the ATR. I will release an example exploit for this later this year. Other options for exploitation would be the SIM trace project which is meant to do men in the middle on SIM card communication, but you can also use it to emulate a smart card. And apparently, there are also certain Java cards which allow you to change these RTLs, but so far I was not able to get my hand on one of them. If somebody here knows more about this, please talk to me. I'm interested in not writing basic anymore. Yeah, for Ubico, this is also in the part where data is also copied from the card, where the responses are copied from the card into the buffer of the one calling the API. And what they are doing, they are checking if the response is small enough to fit in the buffer. And if it's too big, they write an error and continue copying the stuff into the buffer which is too small. Yeah, I mean, it happens, right? So what does this look like? As I said, I was mostly interested in the lock-in process. So I've used this one to write an exploit, exploiting lock-in. The username is not relevant as long as it triggers a request from the card. I left all the debug stuff in, so if you want to watch it again, you can see what's actually happening. You can see there's some shell code. Further down, the return address is all written to execute the shell code. And after a while, you get your shell. And the nice thing is since the whole PEM stuff is running through the root shell, so you don't exploit the lock-in for this user. So you don't exploit just this user, which you maybe try to lock in for, but yeah, you get to root access. And as far as the scene, also on Windows, stuff runs with the elevated privilege. So yes, might be interesting to play around with there as well. But as I said, I found some bugs, but I was not interested in debugging them. How do you approach this? My approach was reading code and do some fuzzing. The fuzzing found way more bugs, obviously. Most fuzzers currently are file-oriented. So if you want to fuzz something like a protocol, you have to tweak it a little bit. What I abused was that the API with the transmit call tells you how much a buffer or how big the buffer is, and basically whenever it's called, when the transmit API is called, I copy everything into the buffer from a file. So yeah, in this case, you don't have call-handling like when fuzzing network sockets. So I always fill the whole buffer, which is at least out some corner cases, but worked for me quite well, and I was able to trigger a lot of code paths by this. This is what my OpenSC fuzzing setup looked like. I use AFL. This AFL called a helper tool, which contains some test code. I modified the test code so that just give me all the certificates and try to do a signature part that's triggered. This calls into OpenSC, which calls the card driver, and the card driver then calls my fuzzing code. And the fuzzing code then reads everything from the file. Since I did not only want to fuzz OpenSC, I also wrote libraries which helped to fuzz the PCSC stuff on Linux and on Windows. So in both cases, you preload a library, which intercepts the calls to the driver, the calls to the reader driver, and inserts malicious data. This wasn't enough. Tavis or Monday ported the Windows Defender code a while ago to Linux, so you could load the Windows DLL on Linux to fuzz it there, which gives you nice beatups and sometimes also more findings since you can control most stuff. I have beaten it enough to get the Windows smart card drivers running on Linux as well. So yeah, the code is available. You could download it, play around with this. If you have any questions, give me a mail or if you have patches, send them to me. Yeah, most of the times memory corruptions are fun and interesting, but the logic bugs are the more interesting issues because they tend to stick around longer, they're easier to exploit. This is what I found in the PAM library. The login process is a little bit different from what I showed you earlier. The random numbers they generate who have the card signed, they need to be very high entropy, right? If you have a card signed the same random nonce twice, you can replay attacks. So where do you get good random numbers? Yeah, from the smart card, right? So if you get them from the smart card and the smart card can choose what the smart card itself has to sign, you can do a replay attack again. If a user is inserting his card into a malicious computer and tries to log in there, you can get the random number signed by the user and then say, no, you're rejected, you're not valid, but then you have a random number and you have the signature for it and can modify your own smart card, your malicious card to replay attack this login at another computer and a valid computer to log in as that user. There are some roadblocks to all the exploitation stuff and because you have no interaction, if you have a pre-programmed smart card, the channel back to the smart card is quite limited. So if you need to abuse information leaks, that's an issue. But in the end, if you can control a bit of memory, that might be enough in the login case. As a takeaway, think about your trust models. The smart cards are intended to make you more secure, but they also hugely increase your attack surface. So that's something you should consider. Yeah, thanks everybody for listening.