CyberWire Daily - Exploits and vulnerabilities. [Research Saturday]
Episode Date: December 2, 2023Ryan from Bishop Fox joins to describe their work on "Building an Exploit for FortiGate Vulnerability CVE-2023-27997." After Lexfo published details of a pre-authentication remote code injection vulne...rability in the Fortinet SSL VPN, Bishop Fox worked up a proof of concept demo. This research share how they were able to create that proof-of-concept exploit, step by step. The researchers state "Our debugging environment consisted of a FortiGate 7.2.4 virtual machine which we modified to disable some self-verification functionality. After bypassing these integrity checks, we were able to install an SSH server, BusyBox, and debugging tools such as GDB." The research can be found here: Building an Exploit for FortiGate Vulnerability CVE-2023-27997 Learn more about your ad choices. Visit megaphone.fm/adchoices
Transcript
Discussion (0)
You're listening to the Cyber Wire Network, powered by N2K. of you, I was concerned about my data being sold by data brokers. So I decided to try Delete.me.
I have to say, Delete.me is a game changer. Within days of signing up, they started removing my
personal information from hundreds of data brokers. I finally have peace of mind knowing
my data privacy is protected. Delete.me's team does all the work for you with detailed reports
so you know exactly what's been done. Take control of your data and keep your private life Thank you. Hello, everyone, and welcome to the CyberWires Research Saturday.
I'm Dave Bittner, and this is our weekly conversation with researchers and analysts
tracking down the threats and vulnerabilities, solving some of the hard problems,
and protecting ourselves in a rapidly evolving cyberspace. Thanks for joining us.
We had actually all been in a training doing heap exploitation the week before this vulnerability
was announced. And so as soon as we saw a major heap vulnerability come up,
we all wanted to take a look and actually try to use what we had just learned
and write this exploit.
That's Ryan, a security researcher at Bishop Fox.
He asks that we not use his full name.
The research we're discussing today is titled
Building an Exploit
for FortiGate Vulnerability, CBE 2023-27997. Yeah, the timing is everything, right? Yeah.
Yeah. Well, let's walk through it together here. Can you take us through step by step? How did you and your colleagues approach this?
So initially, when we started looking into it, we just went and tried to follow the blog post that Lexfo, the original researchers, Charles Fole published.
Charles Fole published.
So they have a really detailed write-up of all of the steps that are required.
And so we just tried to replicate that.
So we started by setting up an environment
with a vulnerable system.
And I used Fortinet on an ESXi system just at home
and figured out how to configure that,
figured out, okay, I am able to hit this endpoint
they're talking about,
and then worked on just being able to get
a crash proof of concept
because that, in theory, should be pretty easily.
And then once we actually had a crash proof of concept,
I worked on trying to get a debugging environment set up,
meaning installing GDB, being able to have a root shell,
because Fortinet appliances don't actually,
well, they try not to let the user obtain a Linux shell.
They don't even have a proper shell installed.
If you run bin sh, it won't drop you into a shell.
So there's a process of setting up this
debugging environment. And then once we had the debugging environment
and we had something that could at least cause this to crash,
then we could continue on with writing the rest of the exploit.
Well, let's back up just a little bit. I think then we could continue on with writing the rest of the exploit.
Well, let's back up just a little bit.
I think, as you pointed out in the research here,
that this bug is a heap-based buffer overflow.
Can you describe that to us for folks who may not be familiar with that?
Yeah, so in most programs you have two areas that you store data. One area is the stack, which is typically for temporary things. Maybe it's only used for the lifetime of a certain function. But if you want
something that's kept around for a long time, or maybe you have a lot of data, you'll allocate in the heap. And so the heap is just a big area of memory and you have
a code that will manage this area and you can request, okay, I would like 1000 bytes,
call a function, and it will return a pointer to an area where you can use 1000 bytes. And then
when you're done with that area, you say, okay, I no longer need it,
free this area, and it can then be reused.
And so with a stack overflow,
there's a lot of other program state
that is stored on the stack.
And so if you're able to manipulate that,
it can often be pretty easy and pretty deterministic
how you would turn stack overflow into a full exploit.
But on the heap, there is a lot of other stuff that is using it.
It's a lot less deterministic, and there's a lot more work that needs to be done to manage
the layout of the heap.
lot more work that needs to be done to manage the layout of the heap. And there's less program state that's directly usable to get code execution. There's often a lot more setup and crafting fake
objects and a lot more really deep stuff that you have to do to actually get a successful exploit.
to actually get a successful exploit.
Well, walk us through how did you trigger your first crash?
Yeah, so the actual bug relies on a difference between using two definitions of the size
of the request that you're sending.
So one definition is just the length of the request. It's a string, so it can
check how long the string is. The other definition is that there's a size field embedded in this
message that you're sending. It actually misinterprets the sizes. And so if you send it a message of one size, but then you set the length field to an extra thousand bytes, you can corrupt a bunch of data that's out of bounds of this buffer.
There's some amount of manipulation you can do to make sure it crashes.
Sometimes it won't crash, but if you just send a bunch of requests where the size field is longer than the actual length of the message,
eventually you will overwrite something sensitive and cause the application to crash.
Thank you. continue to rise by an 18% year-over-year increase in ransomware attacks and a $75 million record payout in 2024.
These traditional security tools expand your attack surface with public-facing IPs that are exploited by bad actors
more easily than ever with AI tools.
It's time to rethink your security.
Zscaler Zero Trust Plus AI stops attackers
by hiding your attack surface, making apps and IPs invisible, eliminating lateral movement, connecting users only to specific apps, not the entire network, continuously verifying every request based on identity and context, simplifying security management with AI-powered automation, and detecting threats using AI to analyze over 500 billion daily transactions.
Hackers can't attack what they can't see.
Protect your organization with Zscaler Zero Trust and AI.
Learn more at zscaler.com slash security. So you achieve your first crash here, then what do you set out to do next?
So once you're able to achieve a crash, you want to start to make this a more controllable crash. So instead of writing to some unknown area in the heap,
you want to actually know that immediately after my buffer
is some object where there is a field
that would be useful to overwrite.
So you try to set up the allocations and deallocations
on the heap such that when you overflow your buffer
and write data out of bounds,
you are writing to something that you know
and you can overwrite in a much more controlled way.
So instead of trying to generate a crash
just by throwing random data,
you want a crash where you actually know what you're doing,
control what you're overwriting,
and get a more controlled crash.
Are you able to read the heap ahead of time
to sort of map out what exists in there
and how it's being allocated?
No.
So in this case, you would rely on knowing
how the program works
and understanding that even though it can feel non-deterministic,
there is a level of determinism where you can control exactly which data you're sending
and know that, okay, if I send this data, this will be the actual layout of the heap.
So in this case, each time you make a request,
there are two buffers that get allocated in this region that you're manipulating.
And the first buffer is a structure that is set up for the SSL context.
And the second buffer is a structure
that contains your actual data.
And through a bit of manipulation,
you can swap that order so that you have your buffer
followed by this SSL structure.
And as long as you do your best to minimize any other noise
and control the exact allocations that are occurring,
you can make sure that you reliably have this layout.
What is your ultimate goal here in this exercise?
What are you looking to achieve?
The ultimate goal is remote code execution.
With this specific setup,
there's a pointer in this SSL structure
that is a code pointer.
And you want to overwrite this function pointer
so that when it gets called, it jumps to code
and you can hijack that code flow
and obtain and use it to then create a ROP chain
and gain arbitrary code execution.
And so ultimately, how did you end up doing that?
What were the rest of the steps that were necessary here?
So we used this function pointer to make a call to adjust the stack pointer to the beginning of the SSL structure.
From there, we were able to have sort of complicated ROP chain that adjusted the stack pointer a few more times
until it eventually pointed to data in our initial buffer, which we entirely control.
From there, we could set up arguments for a call to system or popen or any other function.
And we could use that to basically run arbitrary commands.
basically run arbitrary commands.
And because, like I said earlier,
Fortinet doesn't actually have a bin SH or a shell,
we were able to use the node binary,
so it does use node for a web server,
and we were able to create a reverse shell with node where we run node from exec.
I believe we used exec L specifically.
Now, help me understand here, because one of the things you point out in your research
is that the heap was not mapped to be executable.
So you had to get around that.
Are there particular details you can highlight with that part of the process?
Yeah, so typically if you do have controlled,
writable, and executable memory,
you're able to just directly jump to that code.
So instead of doing this complicated drop chain,
we would just set the function pointer to point to data
that we control and execute it as code.
But in this case, we have to do this more complicated setup where we point the stack pointer to data that we control.
And then we're able to reuse different parts of the binary that is already in memory and executable.
And we essentially run the last couple instructions
of a function and then let it return.
And then it'll jump to the next address on the stack,
which we also control.
And you keep doing that in building up
these little ROP gadgets,
these gadgets that do one small operation.
And by combining a bunch of these gadgets
where you're reusing code from the existing executable in memory,
which is mapped as executable,
you can actually still obtain arbitrary code execution.
What was it like for you and your colleagues
when you ultimately achieved what you'd set out to do here?
I mean, it sounds to me like this journey was fun. What was the payoff like in the end?
Yeah, so it's, of course, always exciting when you get that first connect back with your
reverse shell. So I was very happy when I finally got that working. We were also able to actually create a scanner that we could use
and we released to help others identify what's vulnerable.
And the payoff for the company was, of course,
that we could go test on customer systems and say,
hey, you're vulnerable, here's proof, and get people to patch.
So there's really a lot of, for my team, it was mostly just really exciting.
But for others, there was definitely a positive impact on their security awareness and posture.
Well, and based on the information that you gathered here, what are your recommendations
for folks out there who are responsible for securing their organizations? Any words of wisdom to take away from this exercise?
Patch. Just make sure you're patching. I mean, this is an unauthenticated remote code execution.
It is a heap vulnerability, but we were able to develop a working proof of concept within a week.
No doubt other threat actors would be able to
do the same.
The fix is to patch your system, and please do that.
Our thanks to Ryan from Bishop Fox for joining us. The research is titled Building an Exploit for FortiGate Vulnerability, CVE 2023-27997.
We'll have a link in the show notes.
Thank you. ThreatLocker is a full suite of solutions designed to give you total control, stopping unauthorized applications, securing sensitive data, and ensuring your organization runs smoothly and securely.
Visit ThreatLocker.com today to see how a default-deny approach can keep your company safe and compliant. studios of DataTribe, where they're co-building the next generation of cybersecurity teams and technologies. This episode was produced by Liz Ervin and senior producer Jennifer Iben.
Our mixer is Elliot Peltzman. Our executive editor is Peter Kilpie, and I'm Dave Bittner.
Thanks for listening.