Hacker Time
Presented by: Evan Johnson
Originally aired on May 28, 2021 @ 11:30 AM - 12:00 PM EDT
Join Evan Johnson as he speaks with security professionals about recent security news!
English
News
Security
Transcript (Beta)
Hello, welcome to Hacker Time. I'm your host, Evan Johnson from the Cloudflare product security team.
This is the number one security show anywhere in the world right here on Cloudflare TV.
And today, we are going to finish up... Well, we're going to keep working on what we started, Honeypot D.
We started it a few weeks ago and I had to take off last week and maybe one other week.
But we're not calling it quits on this project.
And we're going to get something out the door, finished working.
And today, picking up from last week, last week, or two weeks ago, when we worked on this, we got the most basic framework set up around building a honeypot.
And we made all sorts of these object oriented things going on here with runnables and all of that.
I think I got some of it wrong. We'll see. We'll keep working on exactly the object oriented parts of this at some point.
But today, we've set up one listener, an HTTP listener for a honeypot.
And today, we need to get the notifications working.
And we're going to do that with the Twilio API.
I think it should go relatively successfully where I can start getting text messages on my phone.
I'll make sure to show one as it comes in. And I'll start getting text messages on my phone from the honeypot when people access it.
And this should get working end to end today.
We'll see how it goes. I have all the API keys and everything set up for the interactions with the Twilio API.
And so just a refresher before I dive in and get deep in the code, honeypots are a really cheap security tool.
They provide detection capabilities and cost almost nothing to deploy just as a fake service.
So you deploy a fake service.
And then anything that accesses that fake service because it's not real, you can assume is malicious or has malicious intent and receive an alert.
And so in a corporate environment, in a large network, in an area where you don't know quite, as a defense in depth mechanism, honeypots provide really, really cheap detection capabilities and cost very little to deploy.
So there's some frameworks out there.
There's like the HoneyD, which I think was maintained by a famous engineer.
I can't remember their name, but HoneyD has been around for a while.
And I haven't actually gotten it working myself. I have a friend in college who's a big fan of HoneyD, but we're building our own because that's what we do because we're hackers.
Okay. So let's start getting this working. I've got my handy dandy batch terminal here with my TMUX session set up and everything.
And the first thing we're going to do is we are going to make a notification provider.
So let's go to honey and let us make we've got three directories, CMD for running our honeypot D, honeypots, a directory filled with all of our honeypots.
And then last we need like a notification directory or something.
And then we can go to notification and we're going to want actually something similar to the way we did it.
So we did our honeypots package and the honeypots package.
We tried to do this object oriented stuff and I spent a lot of effort on it, but I don't, it's not quite right.
We'd like to provide a unified interface that all notifications and all honeypots can implement.
And so I'll try again, I'll give it another go and see if I can fix it this time around.
But package notification, is it notification or notifications?
Notification. Great. When in doubt, avoid using plurals while programming just because you'll be consistent if you always try to avoid it.
Okay. So type notification is going to be an interface and I always forget how to make Golang interfaces.
So let's Google it.
Golang interface. I always forget if there's the func there. I don't think there is a func.
Yes. Okay. So it's just the signature of the function. Notify. It will return an error.
We'll start there. That's it. And then let's start making a Twilio notifier.
Twilio.go.
And all we need to do is make a notification.
What's going on here?
All right.
We need to make a notify function here, but I'm a little worried. Okay.
Notify error. And let's pull up our this.
So we have to do post to this. This is a big, long URL. So let's start.
Sms.
Twilio.sms. This is not the automatic go here with the underscores and all of this, but I don't care.
And right here, we need a percent S, because this is actually our account ID that goes into the URL.
And so we can do one of these. Word is going to hack this.
This is not production quality code. Let me be clear. Not how we want to do things.
And I will read this from another. This is complicated.
So the way this is working, I have an environment variable with my Twilio account ID in it.
And basically, I need to read the environment variable, assign it to a string, and use that for the post request.
I'm trying to make this too clean, and I'm just not going to have any of that.
I'm not going to do any of that.
Okay. So API endpoint.
The uglier, the better, I actually think, because we can improve it. API endpoint.
And then last, we're going to have, we need an OS.getend here. Or end.
No, we need a getend. Actually, we need a lookup end, based on how this is going.
And we will get Twilio. I've got my environment variable set up here with the same name.
And SID.
It's not okay.
So we're going to look up the environment variable and assign it here.
And if it's not okay, we want to...
Actually, if it's not okay, fine.
This is really ugly.
For some reason, my brain's not working, and there's definitely a cleaner way to do this.
It's definitely a cleaner way to do this, but it's too early.
I guess my brain's just not working.
Okay. Let's start here. Let's actually print out. More than welcome to print my account SID.
And it should be an issue. Return nil. Okay. So all this should do, if we hook this up to our code, when we receive an API call, all this is going to do is print out my account SID, which is totally fine.
We're just wiring things up right now.
We actually want to go to Honeypots.
And then let's just... Right now, when our Honeypot gets a hit, we're doing nothing.
Let's print out Quilio.notify. Okay.
This will probably work.
Honeypot.
Okay. Let us do go run tmd, all of this great stuff. Undefined Quilio. Yes.
So I don't have go imports enabled.
So there's going to be a lot of things that need go imports here. Yeah.
I'm going to need OS here. Yikes. I must go on, but not having to go imports is pretty painful.
If I do say so myself, we've got OS and that's really all we need in the Quilio package.
And then we're going to need to do here.
It has .com, my whole thing here. Notation Quilio.
And this should actually, we shouldn't get an issue anymore. Okay.
It is now running port 80.
8080. And if we curl it, we should see a print statement. Yep.
Okay. So that printed out my SID, but it didn't read properly. What a mess. Yeah.
If we're going to make this ugly, let's just make it ugly. And I actually need to source my dash RC here.
And I think this will actually print out. Wow.
I don't know why it keeps asking me if I want to allow binding to port 8080. Echo Quilio account SID.
So that's my SID that should be printing. Why isn't it though?
Oh, yeah.
This is why.
Okay.
This should work. Sure. That's what every programmer says every time they run their program.
And when I curl this, it should print my SID.
Look at that. It does indeed. Okay. So we have printed out the SID, which means we're reading the secret from, it's not a secret.
There is a secret in there though. My API key. We're reading the SID from my environment.
Next up, we need to read all the other stuff and make an actual HTTP request to the Twilio API to notify me on my phone that somebody has accessed my honeypot.
So what we are going to do is we have SID. We need auth token as well.
I'm going to change this one more time because I just don't like it.
So we're going to do a get end instead and just check that it's not nil.
I think that'll be better or not empty.
So instead we're going to use this, which returns a string and then just check to make sure it all works or make sure that all the strings are set.
So instead of having all this stuff, because this is really, I just don't like looking at this.
So instead we're going to do this and auth token will be here and then we'll, if SID equals an empty string or auth token equals an empty string, we can log fatal and tell the user that or log fatal and tell whoever's running this program that.
Okay, so we have the envar reading complete.
There's actually a few more. So there's two phone.
Oh boy, I can't remember what it is. That's my telephone number and from phone.
I'd rather not expose my telephone number to the screen.
So if I guessed those improperly, we'll just run it first thing next time and we'll do all the work and get the satisfaction of seeing the SMS come in and the notification come in next episode.
Okay, so we have, so let's just check.
Okay.
Hey, I think it worked.
I think they're all set. Great. Okay, so we've got plenty of time to make this one API request to Trilio's API.
So let's do it. So this is the actual HTTP request and it looks like it's sent all over like a post data thing where we're just going to use body from two and then this is basic authentication.
So going HTTP basic off.
I believe there is a whole thing for that. Or we can just add the header ourself.
But okay, so the things we have to do, we have to create a new HTTP request that has, that's a post, set the body, and then use basic off.
That's all. This is easy. Let's do it. Okay, so if you've got new requests, we're going to do going HTTP new request.
Great artist deal. We're just going to copy and paste the new request code.
We don't actually want the post. We want new requests because we're going to add a bunch of stuff to it.
Okay, so we will also need, we have a request and an error.
If vector errors people, even if it's like a chore.
Also in notify, we probably don't want to crash because if there's an issue with the honeypot, you just don't want to crash and not have it run.
You want your honeypot to be running.
Oh, and then we are going to send it to post. Great.
And then we will add, we need a client too. So let's make our HTTP client. This is very dense code.
There's a lot going on. We've checked, we've made our HTTP client and then post form.
Oh, look at this stack overflow with the answer for us.
We're hacking together our our thing one copy paste at a time.
Okay. So is this doing what we want it to do? It's doing a post and then a new reader data in code and data is, it appears to be upset of URL values.
Yes, this will do exactly what we want it to do. Okay. So we are going to instantiate a new data thing here.
We don't want name and foo. We want body.
We want all the fields that we saw in this Twilio API doc. So body, we want hello there or security notification from honeypot.
Let's start there. And then from, we want from phone.
And then to, actually it's not to phone, it's just phone.
Inconsistencies make things harder. And then to from, and then we need to do the basic part of this.
Very important, but this will be also in code.
And then within that is going to be strings new reader.
This takes a reader here. So we've created a new request. It's a post to this URL.
And then we're writing all of this data being read into the proper format to this place.
The only thing we're missing is a basic authentication.
And there are two ways to do that.
We could either do that the hacky way and implement it ourself, or we could find where, how to do that in a, in a, in the actual go package.
So, and my go is too rusty to remember.
Okay. With this, with new requests, a request has a basic off thing.
Request has a method, a proto, a header, apply content length, close form, post value, gang, trailer, remote, add, request URI, TLS, response.
Okay. So they don't have a helpful, basic auth is implemented as a header.
Here we go. Set basic auth. Okay. So the way basic auth is implemented, it's, you'll see it a lot of times as a, as a username colon password and in a, in a URL.
And it actually gets sent over as a header, as an HTTP, as an HTTP header.
It gets interpreted as one. So we just need to add rec here, set basic auth, and we need our auth token and SID, and we're off to the races.
This should just fully work. I doubt it'll work the first time.
We also need to add HTTP URL. Is it net URL? We need to URL.
The URL packages net URL.
That's correct. I think it's net HTTP. And then log, we have log.
Strings.
This is really annoying, not having, not having, going ports, which just takes care of all of this for you.
Let's just try it. They'll tell us what's missing.
Oh, undefined, a bunch of undefined stuff. 14, 29, 30, 39. We actually needed this.
27, 28, 37.
So 37, we need to return here. We should actually not be fabled.
Oops. Since the function returns an error, we should return an error instead of handling the error ourselves.
And then imported and not used log.
Now log is no longer here. The joys of programming.
28 and 29, last but not least. It's all lowercase.
It's not a... And I think we're in business now.
Client declared but not used. Oh, we make the request and never use it.
Client.do rect. All right, we've got two minutes left.
I hope I'm getting a text message here in just a moment.
Oh, no.
Error notified. Oh, no. That is too bad. Well, a lot of buildup this episode to be let down by a code not working on our very first run.
Let me just see if I can debug it quickly. Actually see a debug statement here.
I think we actually messed up some of the environment variables.
I'll bet this works pretty closely.
And we're almost out of time for this episode. So this was really productive.
It might not seem like much. Only one API call. But we have the cheapest really effective form of detection possible.
And so we'll talk more about it once this gets fully working.
Next Friday, the very first thing I'll do is demo this working.
And then we will, from there, I'll clean up the code a little bit.
Next Friday, this schedule will be, we'll see it working end to end.
We'll clean up the code a little bit. We'll talk about new features to add.
And we'll talk about some use cases, make it useful. So thanks for watching.