Join Evan Johnson as he speaks with security professionals about recent security news!
Good morning and welcome to Hacker Time. I hope you all can hear me. I'm having a little trouble with our streaming platform.
Unable to kind of pop up the window and see if I'm muted or not, but I assume I'm not muted and welcome to Hacker Time.
I am your host. I really appreciate you being here to watch Hacker Time with me each week and this is the number one security show anywhere.
I'm from Cloudflare's security team.
I'm Evan Johnson from our product security team and we have a jam-packed show today.
It's my favorite 30 minutes each week and I'm here to do two things today.
One, we are going to actually finish, I've been saying this for two weeks, we're going to actually finish this live programming that we've been doing.
We're building a website on Cloudflare Workers, a secure login flow, and it's kind of a toy but also some serious engineering work is going into this and it's really showing the might of Cloudflare Workers and our edge computing platform.
And then the other thing I'm going to do is talk a little bit about CVEs and great blog posts I read and so without further ado, I got everything working on our technical difficulties all sorted out and we are so I'm good to go.
I am going to start out by first presenting this blog post.
I read this maybe 20 minutes ago and it is called, I've never read any of this other, this person's other writing or anything, but this really resonated with me.
This blog post, it's called Security Scanner That Cried Wolf.
And the idea is that a lot of security scanners get hooked up to whomever's environment and they start just producing results.
It could be a Docker security scanner, it could be a network security scanner, it could be for web applications, could be anything.
And this person hooked up a fresh Debian Buster Docker file.
They updated it all the way and then rebuilt it and then hooked it up to an image Docker security scanner and they found 62 security vulnerabilities in this one Docker image.
62 CVEs and that is really frightening.
If you are not a security person or even if you are a security person, isn't hearing that your software has or your infrastructure or whatever it is, has 62 security vulnerabilities is horrifying.
And so, and they call this out, this is terrible.
And they kind of go off and make the point that if everything has security vulnerabilities, then nothing has security vulnerabilities.
They say that every image, every website, everything has security vulnerabilities, then why even try?
Why even try to stay up to date? This person's updating their Debian Buster image and with the most up -to-date stuff, they are still completely vulnerable.
How is that possible? And so, they kind of say, they want to go out and say, why do scanners cry wolf?
And I have my own opinions about this, but they say that these aren't actual security vulnerabilities.
It's not something that can be fixed within the boundaries of a stable or a long support release and it's so trivial that there's no point in fixing it and the upstream maintainers have decided not to release a fix.
So, it usually boils down to someone in the chain thinking that the vulnerability doesn't have any impact or it's not serious.
And that would be really bad if something was really serious and somebody along that chain says that it's not an issue and so it doesn't get patched.
But in this case, what they're kind of pointing out is that when software in Debian is found to be vulnerable, then if it's a core util, like in a fresh install here, this fresh install of Debian will have a number of software packages already in it.
And if one of those is vulnerable, then the maintainers of that software have to understand the vulnerability, understand its criticality, make a patch, release the patch.
The Debian maintainers then need to make sure that that patch is available to Debian users through the Debian app repositories.
And then that package is available to the world for consumption. And so, they go through a number of vulnerabilities.
This one's listed as high.
This one is listed as low. And this one is listed as severity unknown. Severity unknown is even scarier than high in my opinion.
And then they compare it to Red Hat.
And so, they have some ideas about making security scanners more useful.
And they have some good ideas.
So, I have my own opinions here. And so, this blog helps me write down some of my thoughts.
And I wanted to start with... I'll pull up the CVE database here.
So, the CVE project is maintained by MITRE Corporation. And I think they receive funding from the US government to do this.
And it's a very worthy cause.
But there's some problems with it. Let me just type in Ubuntu and see what comes up.
This is probably very small to see. I'll make sure to enlarge it for everybody.
You type in Ubuntu. And I'll just click one. And here, I want to point out the things that I think are the problems with CVE and the general ecosystem.
Starting with CVE, I would say one, CVEs do not apply to cloud or service providers.
So, if you are using a software as a service, and there's an issue with it, that is out of scope for the CVE project.
And so, cloud vendors, they can release advisories and tell you that there's a problem that you need to address or that they addressed.
But CVEs are only for software you download and update and patch.
So, the purpose of CVEs is to advise everybody using a particular software package to go and patch it.
And so, it doesn't apply to all of this cloud stuff where there's no patching that you have to do.
So, I think that's kind of a missed opportunity for CVE because so much of what the industry has turned to is this cloudy stuff.
So, two, just looking at this, it's written like, well, it's not structured data.
So, there's an identifier field, a description field, a references field, who assigned it, when it was created, and that's about it.
The version numbers, if they exist in the CVE, are written in plain English.
They're from this version to this version. And there's no kind of classification of whether it's a remotely exploitable vulnerability.
If it is locally exploitable, there's no classification of severity outside of the box.
They use CVSS for that, which is outside of the CVE data fields. But it is unstructured data.
And so, in a world of APIs, in a world where it's systems talking to other systems, and you might want to integrate with the CVE database or you want real time updates, this kind of stuff requires a human to read it, understand it, and own it.
And if you ever want to be able to handle all of the CVs, and that's just not a good way to do it.
So, that's kind of a missed opportunity for CVE as well.
There are vendors and stuff that you can purchase more structured data from or whatever.
But it's overall should be free. Everybody should be able to consume a CVE API and get information about vulnerabilities.
I would say that normally, on the average case, one problem with CVEs is because this is unstructured data and this is written in plain English, you have a lot of cases of ambiguity of version numbers.
So, here, 2 .4.202, 2.4.43, it's kind of specific, but it's more specific than most of the CVEs that you'll see out there.
But we don't know how many software versions were released between this.
It could be 23 Apache versions.
It could be three Apache versions. You're not really sure right out of the box with the CVE exactly how many versions are vulnerable to this.
Here's another one.
In the Linux kernel, 5.5.0 and newer, this vulnerability was fixed in 5.6.1, 5.5.14, 5.4.29.
And if you're looking for a way to kind of map what you're using and in a programmatic way, determine if it's a vulnerability that applies to your environment, then this kind of stuff is really difficult to parse because all of the different software packages have different version strings.
A lot of them use the major, minor version string like this.
I'm forgetting the actual name for this format, the major version, minor version, and then revision, I think.
But a lot of people do use that. A lot of software packages do use that, but not everybody.
So if you're trying to build a programmatic way to kind of parse all of the CVEs and understand how they apply to your environment, good luck because the versions are a big blocker to that and a big challenge because they're kind of sprinkled in throughout this English description of the vulnerability.
And then probably my last complaint is a lot of these CVEs tend to lack context.
And so you can have a CVE and it doesn't really take into account your threat model where they might say something is a critical vulnerability, but it's a critical vulnerability only in the case of a kind of shared computing model where multiple parties are on the same host and one party can raise their privileges and kind of read data of another party.
And for businesses today where everybody rents their own servers or have their own infrastructure or are using cloud service providers, that type of issue is not really something that applies to them.
And yet they still have all of these CVEs in the Linux. You might have a Linux CVE that allows privilege escalation and that is very serious and something that you want to prevent.
Like one process could potentially, if compromised, could raise privileges and compromise the whole host.
But most people, if they have one process that's compromised, they're just going to assume the entire host is compromised.
And so it doesn't really apply to most people's environments.
So a lot of these lack context that most businesses aren't sharing hosting providers or aren't sharing hosts anymore with other businesses.
And local versus remote. Remote is definitely more critical than local and CVE doesn't really account for that.
I guess it kind of does by way of CVSS.
The CVSS scores for remote will be higher, but the way CVSS works, it's really easy to have a critical local issue that it can feel really bad saying this is a critical issue, but I mean, it doesn't really apply to us.
It kind of puts people, it can take a security engineer reading this and they're kind of torn because they're saying seem critical, but they're also seeing, well, I don't really agree that this is critical for us.
So I see CVEs lacking context regularly. But that was kind of a brain dump of my ideas, reading that blog post.
And I don't know if anybody has thoughts or if you do feel free to reach out to me on Twitter or by email.
A lot of you know how to find me and hopefully I got you thinking. I want to write about this topic.
So it was nice to jot down my ideas and kind of spitball them live on air for you.
And with that, I'm going to start programming and I will reshare my screen to show my entire screen.
And let's do it.
Let us get the programming going. So over here, I am going to have my TMUX session.
Let's make this much larger. I actually have the text on my phone enlarged just like this.
Makes it so much easier on my eyes.
But I can only see a few letters at a time.
Let's start our new TMUX session and change to our Cloudflare TV directory.
And we want to go to ejcx.net.
Here's our nice login form. Yeah, where were we?
Let's get started. So we have a signup procedure. Let's create an account, ejcx99.
Password is ejcx99. We can create an account. It forwarded us back to the login page where we type in ejcx99, ejcx98.
Let's make sure that we're not getting logged in.
We see error one in the URL field, ejcx99, ejcx99. And we broke it, which is perfect.
We know where to start. So we've got our code here. This was on the login post.
So what did we do here? So we called, we did all of this login stuff.
I think this is probably working. And then it must be in these four lines because I have a catch statement here.
Uh, let's, uh, let's do this. Let's just find out exactly what's wrong.
I don't really want to think too hard. So this should work.
Let's see if it's obvious though. Put session. We're redirecting.
Oh, I wonder if it's this. I had, uh, theorized, let's do this quickly.
I had theorized that, um, these 301s versus 302s were, it mattered. So Wrangler publish.
And as easy as that, our code will get packaged up. And if that doesn't work, I'll, I'll move this catch statement here.
Remember this takes just a second to web pack up our code, check all of our dependencies to make sure that, um, we have all the right stuff and then, uh, talk to the Cloudflare API and push our code.
Okay. Nope. Okay. Let's just, uh, I think this should work, but why didn't it?
Session, put session. Do I use put session anywhere else?
No, I don't.
It could be that. Oh, interesting. JSON stringify is happening here.
That seems like it's unnecessary for me to call stringify before it goes in. First of all, I think it worked.
Okay. So when we call put session, we create this object, we call put session and put session is stringifying it.
And then get session is parsing it. And so where do we call it?
Get session. We don't. Okay. So it doesn't matter yet. Um, whether we call, we JSON stringify it once or twice, we just got to make sure we unstringify it in a consistent number of times.
So you JCRX99, you JCRX99. And we should be able to double check our cookies.
Oh, I don't know how to do that anymore.
Chrome changed the way you, uh, interact with these.
All, and we see, it's going to be difficult for you all to see, but feel free to squint.
Um, you'll, oh, we don't see a cookie here. We see the CFD UID cookie, but the cookie didn't get set.
That's what we need to do. We need to set the cookie and parse the cookie.
Um, so, so we put the session, I believe.
So Cloudflare worker get parse cookie. This is a little funky thing about, uh, there's this get cookie function that we pasted here, but we also need a, like a set cookie function.
And I guess that's best to implement when we do the put session here.
Um, the response probably shouldn't be a redirect.
It should be a response setting a cookie.
Um, okay. So Cloudflare worker response set header, set cookie. Oh, somebody has been here before.
Maybe it was me. So this is the function that I just had up here and we need to pass.
So we need a, like an authentication function. We'll pass, we'll basically use this code where we call get cookie with the request.
We need a cookie name.
I'm not going to do that.
I'll stick to, uh, stick to the naming convention I already had.
So if we have a cookie, we want to get the session.
I'm going a little out of order here.
Get session. Key.
So the function signature is wrong because to get, you should only pass the key, not the value.
That one should be obvious. Um, and I think this will work, uh, if we were to call it, otherwise we want to return false.
Uh, return get session cookie.
And so this is a function we can use to authenticate a request that comes in.
We'll call this auth, this auth function and get back a stringified or a, uh, an object, an object containing who you are or false.
But we need to actually set the dang cookie.
So how do we do that? Uh, we need a author worker response header.
So I always forget how to do this exactly.
So I think it's, uh, when we do a put session, what we want to do is return new response and we will do a blank body.
And what we want here.
It's first, we want headers, right? And how do you actually set this?
Do you have to do new headers? Okay.
A headers object. Okay. Our player worker, that response letter, it will be somewhere.
Okay. So I don't have to do, um, no, so I don't have to create a, uh, so we can create a new response and then we can set the headers afterwards, which is great.
We don't have to do it all in line here.
It'll make things a little cleaner. So we can just do a new response.
I'll do let r, not a great name, but r.headers.set. Is that a cookie?
So we're going to start with this. This is not how you want to set your cookies in production.
Let me tell you, because there's a lot of security features on your cookies, like HTTP only, um, a bunch of stuff like that.
HTTP only. He is set here.
Same site. None. Very good. Secure cookie. All right. Mike Strini is doing all the right stuff here.
I appreciate that. And, um, okay. Domain will be jcx.net.
Source. Does this actually matter? Oh, this is like an attribution cookie.
It matters, but I think this should work. Um, and then we also need a cookie value, right?
Oh, this is the cookie value, right?
And it's been a while since I've done real programming. Cookie string. This would be embarrassing if I can't get it to work.
And I only have a minute. So we want to do cookie string equals cookie.
Equals, um, cookie name.
I think it's correct. Let's see if we can get this working.
I think this will work. It's not pretty, but it will work. Where, when we log in, Oh, no.
30 seconds left. I hope it works on the first try. Otherwise I'll have to sign out with you.
Not going to have time, but this is, uh, thank you for watching me struggle with cookies.
Um, the HTTP or the, these objects, it'd be really great if they had better support for cookies built into the request and response objects, but I understand they're just headers.
It's more of a browser concept. Um, with 10 seconds left, I really appreciate you all watching me.
Um, and it looks like, did it work or not? It looks like it did not work.
Okay. Well, thank you for watching me and, uh, appreciate all of you.
Um, I went a little over time for the live broadcast, but, but thanks for watching and I'll, I'll see you next week where we will get this working.