Firefox JIT Bug - Pwn2Own Documentary (Part 3)

Firefox JIT Bug - Pwn2Own Documentary (Part 3)

Machine-readable: Markdown · JSON API · Site index

Поделиться Telegram VK Бот
Транскрипт Скачать .md
Анализ с AI

Оглавление (4 сегментов)

Segment 1 (00:00 - 05:00)

I was able to follow 2 engineers from Mozilla at the hacking competition, Pwn2Own. On day 1 of the competition, we saw 1 successful exploit against Firefox: an out-of-bounds write in the Promise. allSettled function, leading to a remote code execution. And I wanted to highlight the timeline really quickly because I think in the last video this was not quite clear. So at 11am, the demo happened on stage, and then 1 hour later we were finally able to enter the disclosure room and Mozilla got the exploit details immediately. Engineers started with bisection, which is the process to identify when the issue was introduced, and that process took a while. And also, one of the engineers, Christian, had to ride with us in the taxi back to the Mozilla office. So almost 1:30 hours later, it was confirmed that this issue goes back roughly 6 years. Jan, one of the main JavaScript engineers at Mozilla, looked into creating a fix. And less than 1 hour later, an initial patch was ready. However, Mozilla wanted to make sure that there are no variants of this issue because as soon as the patch is public and Firefox is open source, other hackers could look into it as well, but about 2 hours later, Jan was confident in the fix. Eventually, Freddy, who was the incident manager here in Germany, handed over the incident to Dianna Smith for the night and she then continued handling the release process. But a full release build was not yet created because this also had to go through QA. And this is not a real incident. This is just a fire drill practice run. So they decided to wait for the next day, which is today, because there's another entry at Pwn2Own. So let's go back to the competition for day 2 of Pwn2Own. This USB stick was just sold for 50,000 dollars. What could be that valuable? It's not a crypto wallet, no stolen data, and no state secrets. Just a few lines of code. Beautiful but dangerous code. A zero day exploit in a back room of a hotel in Berlin. The trade went down. They are the ones who bought it. sold it and they will make it worthless within hours. This is the story of 2 Firefox zero days, the world's most prestigious hacking competition, and what it takes to keep millions of users safe. Today is the 2nd day of Pwn2Own and Manfred Paul is already sitting on stage waiting to demonstrate his exploit. But before we see whether he's successful, let's take some time to learn a bit more about his exploit. I was able to sit down with Manfred before the competition and talk with him about his bug, and why he decided to look for a bug in Firefox. I was definitely motivated to look at Pwn2Own specifically. I did want to come here, especially now that they moved it to Germany. It felt like, okay, I kind of need to stop by here and um, would be more fun to do that with a bug. Um, so I looked at, um, Firefox specifically also because I just felt like it, to be honest. Like, um, for me, it's always like a process that's driven by a lot by what I'm motivated to do. And I can't really force myself that much to look at something I'm just not in the mood for. To be honest, like quite close to the deadline, I still thought, okay, uh, I don't really have anything, but, uh, so this was really a kind of a last minute find. Like, um, I don't know, maybe a week or 2 before the actual registration deadline. What is generally your research process? Usually it's like a lot of looking at code and thinking about it this time. I also played around a lot with like the actual JavaScript interpreter and like the compiler and tried to build little programs that really reach the edge cases there. And what kinds of conceptual problems could I cause in, in this particular area of code? And, uh, yeah, at some point I noticed, okay, this is actually like a wrong optimization that happens here. And that could be useful. So when you are looking for conceptual problems, then like other approaches like fuzzing don't play a role in your approach. For me personally, not really. I mean, it's something I'm always like thinking about. Maybe I'll get into it someday

Segment 2 (05:00 - 10:00)

but so far I've really been focusing on code analysis. It really allows me to find a lot of bugs that the fuzzers might miss because like, I think there's a lot of fuzzers running and lots of people are doing it, and it became really popular at some point. And I think like code review maybe got a little bit out of fashion at that point. But there are certain bugs that fuzzers just really struggle with. For example, if you have some really complex construct that you need to even trigger the bug in the first place, or even if you can trigger the bug, even realizing that there's a bug, there's like techniques like differential fuzzing. And then you might catch something like, okay, there's a wrong result there, but even that not everyone is doing it. And if you're just looking for like crashes, a lot of these bugs don't just give you a crash immediately. You have to really work to even get like memory corruptions from it. And so if you just get like a wrong mathematical result from some expression, a non-differential fuzzer will not have any chance of even catching that. Okay, so there were a few important keywords. First of all, he was not using fuzzing and instead read the code and thought about conceptual issues, specifically wrong optimization. If you are more familiar with browsers, this could tell you that this bug is likely a JIT optimization issue. Just-in-time compiler. This is where the browser tries to compile parts of the JavaScript code into optimized native code, and if this optimizer makes wrong assumptions, the resulting native code could lead to memory corruption issues. But he also said that some bugs don't immediately lead to crashes, which makes it hard for fuzzing to find the exact condition to trigger a crash. And that's when he mentioned differential fuzzing. The idea of differential fuzzing is that you are running the same test case or JavaScript code with different programs. This could be Firefox and Chrome, or even within the same engine. Interpreted JavaScript bytecode versus JITed code. In theory, the result should be the same, but if they are different that could maybe point to an exploitable optimization bug. Anyway, he didn't use fuzzing and he found this optimization bug by hand. So let's hear a bit more about how he identified this issue. I think what helps me a little bit is like I come from kind of a mathematical background. So I studied mathematics in university. And so I think that influences my thinking a little bit with this kind of work, where I often kind of try to in my head, prove that a function is correct. And when I realized, oh, wait, this proof doesn't really hold up, there's something that I'm missing there. Then there might be some problem in the code, and then I start to look into it. And of course then you have to look into, okay, how can I actually reach this case? Because just because some objects can be maybe in some theoretical state, um, it's not a given that you can actually like, then build a JavaScript code to reach that state. So that's then the 2nd part. And that's really like maybe the most frustrating part of um, code review is um, I'd say probably like 80 or 90 percent of the time when you think, oh, this might be interesting, it turns out that, okay, maybe I just misunderstood what the code is doing, or I missed some check that happened somewhere completely different. That just catches this case, and there might not even be, uh, like any kind of problem. That might just be that I had a wrong mental model of the state of the whole thing. And for example, in this case, it was really like something where I got it wrong in the past where I thought, okay, maybe there is some conceptual ugliness there, but it's not something that can happen in practice. And then I went back and, um, realized, okay, now there are actual problems with this piece of code. I just wanted to interrupt for some math propaganda. Personally, I'm also not good at this academic level of math, but I'm very convinced that a brain that can analyze and work through mathematical proofs is a very good hacker brain. Mathematical expressions are like code. You need to reason about it and use abstractions as a tool to understand very complex systems. So to me, it's no surprise that somebody who studied math can find bugs in a browser. So maybe use this as an example that you don't need to study computer science or even cybersecurity to become a hacker. But anyway, let's hear what else Manfred has to say. Let's say somebody is starting with Firefox for the first time. Can you come up with like a theoretical path, how that could look like, how that person could end up in that place, like what led to the area where you ended up in. So in this case, the bug was really in like an area that would jump out to most security researchers because it's like, uh, related to actual bounds check elimination. So the actual piece of the code where bounds checks for different, like array accesses, are directly eliminated. And so I wouldn't say that the path to get there is too long

Segment 3 (10:00 - 15:00)

because like, that's kind of a if you read like previous bugs, it's often the goal to get to this kind of area of code right where you... Is this the optimizer you say, who gets rid of bounds checks for optimization reasons? I always find it interesting to hear about the reason to look at code. I mean, okay, you do manual code review, but where do you start in these millions of lines of code? Well, here's the function Manfred talked about: TryEliminateBoundsCheck. And he said a lot of JIT browser bugs are related to bounds checks. So it's an obvious function to look at. But why exactly. Well in JavaScript you can have arrays of arbitrary length. But in native code you always have a limited buffer. So imagine you have a JavaScript loop going over an array of numbers to calculate the sum. If you wanted to compile this to native code, we have here the length of the array, and it will never access any element outside of that array length. So that one would be easy. But now look at this foo function. The iterator i is not bound by the array length, it's going from 0 to 9. And then also the array index always has this constant offset of +5. If we want to compile this to native optimized code, we need to add a bounds check. If we add a bounds check here, is i + 5 now outside of the buffer? Then in every iteration we need to do that expensive check. Ideally we would like to know at the start if a is large enough and we can calculate that. We know that the loop always iterates from 0 to 9. So the largest possible value for i is 9 which makes the largest possible array access 14. So we can add here a bounds check in native code to make sure a must be at least of length 15. But now look at this example. Here we have 2 array accesses with different offsets. Do we create now 2 bounds checks, 1 for a at least length 15 and 20? Well that would be kind of redundant right? The 2nd one overlaps with the 1st one, and this is where TryEliminateBoundsCheck comes into play. This function gets a list of bounds checks, and it tries to replace it with a single bounds check. And if wrong bounds checks are removed, we would have a native function that allows us to access an array out of bounds. What I was looking at was just the bounds check elimination function. Or I should say when I say bounds check elimination, that's what the function is called. It's actually like merging 2 subsequent bounds checks. They might be for different actual indices, but the way that Firefox bounds checks work, they can be merged into basically 1 long bounds check for the whole range of interesting bounds. And this function used some other helper functions that were dealing with quite mathematical concepts. They were dealing with like analyzing basically linear sums of different terms. And so what got my interest there was, there was 2 different modes that these functions work. They can work in what the Firefox developers call infinite mode or modular mode. So what got me interested is that the way this function was built, it didn't really specify which of these 2 modes this other function was supposed to look at. And of course, this means if you get it to do like the, um, overflowing mode where you should actually be using the other mode, then that's very interesting. And then it can maybe get wrong results there. So this linear sum helper function tries to look at array accesses that are linear sums like i + 5 and i + 10. But to do the bounds check properly, this depends on the math space. Numbers in JavaScript can basically be infinite in size, but sometimes you have modulo math. Then whatever the number is, it always bound by the modulo. This is obviously very useful to know for doing bounds checks, or whether you can eliminate/remove bounds checks. And he uses a little trick with OR 0. The basic construct to trigger this bug is somewhat simple. What happens here is that the bitwise OR with 0 will force a truncation to 32bit integers. As you can see here, the numbers are now just wrapping like a signed 32bit integer would. However, by the time this bounds check elimination will run, the bitwise OR will have been eliminated. It got optimized out because OR-ing with 0 is a no-op, it doesn't do anything, so it will see this version and assume okay, this one is always +5 larger than the other one, so it can merge those bounds checks based on those numbers. But the problem is this is not true with 32bit signed integers. If you set i to 2 to the power of 31 minus 7, then i + 5 is a positive value.

Segment 4 (15:00 - 20:00)

But i + 10 wraps around and becomes negative. So the linear sum analysis is wrong. The bounds checks are set wrong. And now you can access memory out of bounds. And here is his basic proof of concept. If you download Firefox from the archive, version 137, you can also try this yourself. First, Manfred writes 1337 into a huge map in memory, so that we have a good chance that when we out-of-bounds access somewhere into memory, we can access these values. Then here's the function that we want to get optimized with the eliminate bounds check during JIT compilation. You can see it prepares 2 array indices where the index depends on x, but each index has a slightly different offset so that we can abuse this bounds check elimination. If we now kind of know where in memory our array is relative to the generated maps, we can access the native buffer array out of bounds and read arbitrary memory, which you can see here. We read 1337. I think we heard now enough. Let's go back to Pwn2Own. And will Manfred be successful? Well, the wish is that they fail. Like as as as much as I like this as like an instrument of learning and getting feedback about how exploits are being written. Of course, ideally I would just like them to fail on stage. Like as as much as I don't want to, like, offend them as a person. Like, I wish everyone to succeed in their aspirations as a person. But of course I want them. I want them to not be able to exploit Firefox. Let's see if Freddy gets his wish fulfilled. Hello everyone and welcome to Pwn2Own Berlin 2025. This is day 3. I am Dustin Childs, head of threat awareness here at Trend Micro Zero Day Initiative, and we have a couple of really exciting attempts that are getting ready to go. If you're not familiar with Pwn2Own, it is the world's premiere competition where we invite security researchers from around the globe to come in and demonstrate their exploits against the latest technologies from some of the big vendors in the world. Right now, we have Mozilla Firefox over here, Manfred Paul with that, then we have Star Labs targeting the Oracle VirtualBox with a kernel EOP. So it should be really fascinating. We're going to start over here with Manfred Paul. So you guys are all set. All right then kick it off whenever you're ready. He has 3 attempts within a 30 minute time period. And those attempts are 10 minutes each. I can guarantee it will not take 10 minutes. Manfred is a former Master of Pwn winner. That is the overall winner of the competition. And for this, all it is, is a web browser to a web page. There's no clicks on top of it. And you got it popped up right there. So what he did is he demonstrated code execution by opening the calculator. So browse to a web page. Boom. That's it. And then you get code execution. If confirmed, that will be worth 50,000 dollars AND 5 points towards Master of Pwn, which is the overall winner of the competition. This is the 1st stage of what it takes to win. The 2nd stage actually takes place in private in a disclosure room where he goes through all of the details. And then we bring in Mozilla. Mozilla is right here and we will disclose the bug to them, and then they start working on a fix. They have 90 days to make a fix. With Mozilla it's usually more like 48 hours. They fix very quickly. So we'll see how fast they patch on this one. So there it is, another successful exploit against Firefox. But if you want to know what happens in the disclosure room and how and when Mozilla fixes the issue, make sure to subscribe for the last part of this series. Have you checked out our online training platform? In this crazy new world of AI and agents, you might think that you don't really need education anymore because they can just hack a website for you. But even if I strongly believe that is the future, that is the case, I still think it's extremely important to have a knowledge foundation, because only with a strong knowledge foundation and good understanding of technologies and all these different systems, you're able to actually prompt the LLMs and the agents effectively and you will be able to realize when they make mistakes. So I still think it's very important to educate yourself and don't become lazy because of AI. Our courses on Hextree are basically micro courses. They are very short and each individual video is very short because we don't want to waste your time with an 1 hour long boring screen recording. Also, our courses focus on fundamentals and by that I don't mean the beginner entry level stuff. I mean actually foundation knowledge to build up to really complex understandings of systems. So you really need knowledge and especially foundational knowledge to use these tools [LLMs] effectively. And I hope with our courses at Hextree, we can teach you exactly that.

Другие видео автора — LiveOverflow

Ctrl+V

Экстракт Знаний в Telegram

Экстракты и дистилляты из лучших YouTube-каналов — сразу после публикации.

Подписаться

Дайджест Экстрактов

Лучшие методички за неделю — каждый понедельник