Cloudflare TV

Hacker Time

Presented by Evan Johnson
Originally aired on 

Join Evan Johnson as he speaks with security professionals about recent security news!


Transcript (Beta)

Hello, we are live on Hacker Time, the number one security show anywhere. And today we are going to get started on our new project.

It's going to be really exciting.

I've decided to name it Honeypot D. And as many of you, I'm sure, engineers, the most exciting moment, there's two most exciting moments in your career.

One is anytime you create a new project. And the second is anytime you delete a lot of code from that project and clean it up.

Whenever you start a new project, it's really exciting.

And so my goal here is to make a pretty simple framework for running honeypots.

There's some others out there. There's Honeybee. I know we talked about Think Canaries.

They're a business that runs them. And hopefully, these should be cheap, easy detection services that you can run that and encode that you can contribute to and read.

And if you're new to Go programming, learn something about Go programming along the way.

And today, the programming we're going to do is a lot of like framework stuff, trying to get the environment and all of the project directories and everything set up in a way where it's really easy to add more honeypots.

It's really easy to maintain the project. And we're going to work through a lot of that.

It's going to be maybe a little bit of a grind because I'm going to implement the Cobra CLI framework and try to get a directory set up where you can easily contribute new honeypot services and probably build the first one and the interface around it.

So yeah, that's what we'll do.

And since this is a security news show, there's tons of security news this week.

The pipeline, ransomware, there's a lot going on.

And a new executive order. And I think I'll cover all that next week.

I want to take some time to really dig into the executive order and read it thoroughly.

But lots of mentions of Zero Trust, lots of mentions of multi-factor authentication, which are huge, huge news.

But I'll address that stuff I think next week or in two weeks, depending on how far we get in this.

And maybe I'll have a guest on to talk about it.

But for now, we're going to do some programming and it's going to be great.

So let's get started. All good projects start with creating the repo and a nice readme file.

So honeypotd, let's make this lowercase because I'm a lowercase kind of person.

And we have created our new repo. And so I'm going to create a new Git repo, add the remote.

And I did do a commit.

We have the log. We have this thing. Okay.

We're already running into problems. This is usually a good sign. It's not an SSH authentication issue.

No idea what would be going on with this, and I'm not going to debug it today.

Let us add... Oh, you can see some debbing I've done.

All right. Well, this is where all the code will live. Actually, I'll try one more thing.

I always have problems with the SSH authentication one. Let me do remote remove.

I'm not a very good Git person.

Shout out to Tony Stuck, who taught me how to use Git my first couple weeks at Cloudflare because I was coming from a mercurial background and had no idea what I was doing.

So shout out to Tony, who taught me everything I know about Git.

So git push-u origin. Unfortunately, everything I know about Git is not a lot, and I don't know why this is not working.

So I'll come back to it. So next thing we do, we need a nice main file.

And so what we're going to use, we need to get our CLI set up and a nice place to run our actual Honeypot D.

So we're going to start with Cobra.

Cobra CLI Golang. And I'm a big fan of Cobra. It can really spruce up your CLIs.

And if you're working with Go, and you can start with basically one of these.

How should we do this? Let me first do... Let's download the Cobra CLI.

I think that's how most people interact with it. That's usually not how I interact with it.

So this is going to be the...

Let's start with main.go. So let us do... We're going to make dir-p cmd honeypot d.

And then we are going to save this as honeypot d.

I'm not used to programming in Visual Studios, but that's what we're doing today.

So some of it's a little wonky for me. Package main. And we are going to do...

Start here.

We need a root command. I'm going to copy and paste a bunch of stuff from here. And then we're going to debug why it doesn't work.

That is the best way to program.

And we need to go get this Cobra thing. Let's do that real fast. And then now our Go import should work.

Yes, it does. So what's happening here init is loading.

When we run this command, we don't have a main yet. So that's a problem.

But init will run before main. It'll add this Cobra command. And then what we need is in main, we need to actually call cmd.execute.

But cmd doesn't exist, which is a problem.

Can probably call root cmd. And this might work.

Why is...

what is... oh, cmd is a directory. Okay. So this is what our... this is what the CLI should kind of look like.

Look at that. It prints out real nice.

It says Cobra is a CLI library for Go that empowers applications. So we can fill in our thing here.

So honeypotd, a simple honeypot daemon, and long.

I'm not going to do a long op.

I'm a long description. I'm a short description kind of person.

And we should have a really nice short message. Usage honeypotd. We have a few available commands that come by default.

So Cobra really spruces up the CLI with very little work.

It says it has a help, it has a version, all this stuff by default.

So you can see that the version command is here. Although the version...

yeah. So each command, each subcommand we have, will get its own little structy thing here.

And then within that, there's a run function, which gets called when you invoke version.

So if we want to say version, we'll say, like, we can do this kind of the easy and the not the best way.

But we can just have a version here.

Version equals 0.0.0. We can have a version string here. And then we are, our version command can just print that.

So let's try to run it. Go run honeypotd version, version.

And it should just print out our version string. Yeah. So this run runs within whenever you invoke the subcommand here that use has.


So we have a basic, basic, basic CLI actually working, which is cool. And the way we're going to add to it if we want to add another subcommand is we'll add this thing.

We'll add a new structy thing with a new use here. We will add it down here, a little bit of boilerplate where we add, in order to add it, a new command, we'll have to call root command dot add command, and then whatever the struct thing that we made.

And then all main is, is rootcmd dot execute. And because our subcommands are added to rootcmd, then the thing should just run nicely without us worrying about it.

Okay. So I want to make a run command. So run is going to be the thing that runs our honeypot daemon.

And print the version number. No long description. We want a short description.

No long description. Run a honeypot. Very simple. And let's just print run me for now.

Okay. And then this is underlined because it's unused. So we just have to add another here.

Rootcmd, add command, runcmd. And this should work. Go run honeypotd run.

Run me. Great. And if we compile this thing to an actual binary, we have this nice honeypotd binary that we can just run.

Run me. So instead of doing this really big go run thing, I use that for development a lot of times, but not as much.

It's not something that, not a good way to run in production since go run will compile and then run it.

You normally want to build your binary and then ship it somewhere.

But that's how I do it in development. But in production, if we were this, we'd have the nice binary here and that's all set up.

Okay. So we've got a run command.

What's this thing going to do? Well, we're going to need two things.

One, we're going to need some type of method to configure what honeypot is going to run.

We need a place to develop the honeypots. So maybe we need three things.

And last we need a, so we need a place to develop honeypots, a place to configure which one's run.

And do we need a third thing? But I guess not. Run needs to sort out those two things.

So configuration of what's running and a method of neatly loading the proper ports, listening on the proper ports, running, instantiating the proper objects and servers.

So from here, what we will do is we will create, I'm going to create a directory called, and we'll start with HTTP.

We'll start with an HTTP. I'm going to start with a general new directory within this.

And we are going to call it, we are going to call it honeypots.

And within honeypots, we are going to define a, the word's escaping me.

It's not a class or an object. A interface.

We're going to define an interface for what all of our servers and honeypots will do.

And then we'll build one that implements that interface. Not a good, not a huge fan of using interfaces everywhere, but this is a reasonable time to use an interface.

And then we just have to make a configuration file that instantiates all the right, instantiates all the right objects.

And then within our honeypot run function, where we have run me, we would just need to call whatever run the honeypot function is defined in the interface.

So this is very much kind of like a object oriented world is a very object oriented way of thinking.

But that's, there, there are merits to that.

Sometimes you don't want to go overboard with your software design, but getting the right design is a good thing.

Okay. So in honeypots, let's make a honeypots.go file and honeypots package honeypots.

All we really need in here is type honeypot interface.

All right.

Let's start with this really simple. We just need a function in here. Run.

And do we need anything else?

I suppose we might need a port. All honeypots will have a port.

We can pass it a struct. Actually we can do a type. I'm going to call this a honeypot runnable.

Let's go full on Java enterprise edition with this, which has its runnable interface.

And then we're going to call this a honeypot and call it a struct.

And within a struct, we're going to have a port, which has a string.

Let's start there.

Maybe an address, level string. And then we want, within our honeypot runnable, we want it to be a honeypot.

So this is kind of the definition we want here.

This is very angry about my syntax. So interface go line.

Let's make sure my syntax is right because something's clearly wrong. So I don't think we use the spunk thing here.

And my Go programming is so rusty.

Let's just pass in a honeypot. Honeypot.

This should work. And it'll return an error. Okay. This is a very basic definition of how we want to run our honeypots.

So the way it'll work is we'll instantiate one of these honeypot structs and call run, pass that struct to a type that has the function run and takes in a honeypot.

So if we're going to get an HTTP one, let's start with the HTTPot.


It's going to need two things.

It's going to need first a package HTTPot. HTTPot.

And then it will need a type.

Well, it'll just need a function that's called run. Type HTTPot struct.

And it just needs a function run.

This is a little confusing, but I'll make sure to rewind and explain what's going on because we are deep in object oriented worlds right now.

But it'll pay off and you'll see why pretty soon.

So run just needs one of these things from the interface.

It just needs a honeypot pointer and it must return an error.

And that's it. Honeypot. Is it honey? Did I do capital?

Yeah, that's not the best. Honeypots. All of these case sensitivity issues.

Undeclared name, honeypot. Okay, we can do honeypot.

Yeah, I have a plural here, case sensitivity here. There's some cleaning up I could do to make this a little easier to write.

And why is this angry? Honeypots package, honeypots.

So these are in the same directory.

Let's do this all in one spot for now. We can have just one big file.

You don't actually need a ton of files here. So we have a run.

This all just works properly. We don't write out of the gate. This should work perfectly.

And within run, I guess the struct doesn't need anything right now.

Within run, what we are going to do is just run an HTTP server.

So going HTTP server. We can just copy and paste the code into here.

And use the data from here to bind a specific address, whatever is passed in.

So listen and serve is a very reasonable way to do this.

You'll recall we did this about a week ago as well.

We just need slash. And we can honestly, we can do nothing.

And that's fine. Just return a 200. And that's plenty good.

And right now, it'll only run us one single honeypot.

It'll just listen on this port. Actually, let me do a bump sprint F here and do a address port thing.

So H dot address. H dot port.

So okay, this has been really confusing, but let me bring it home.

If you're not an object-oriented programmer, or haven't been exposed to a lot of these concepts, you might be saying to yourself, I'm very confused.

And that's fine, because the stuff is very confusing.

If you've never seen the concepts before, or you have no idea what I'm doing, or why someone would spend their time doing this at the very beginning of a project.

But the way this is going to work, when we call the run command, what it's going to do is it's going to parse a configuration file at some point.

It's going to get its configuration from somewhere. And then what it's going to do is it'll say, okay, the configuration file will say, okay, I'm going to set up an HTTP honeypot.

And that honeypot will get instantiated by, we're going to instantiate the port and address here in this struct.

And then we're going to call run. We're going to create an HTTP honeypot as well, in case there's any configuration we want to add here, like specific paths you want to add and listen on, or whatever it is.

And then we're going to call run on that.

And so all this code will need to do, it's not going to care what the, when we run our honeypots, this piece of code doesn't care what type of honeypot is running.

It doesn't care about any of that. It only cares about, does it have a run function and, or a run method, since we're, I'm saying we're in deep in object oriented world.

And, and then it'll just call this run method. And it's very simple.

It makes this code very simple here. And then the other valuable aspect of this is when we're contributing a MySQL server honeypot, an FTP server honeypot, or whatever other type of server you'd like to, to add, you can just, all this code needs to do still is call run, but all, and, and then all you have to do to add one is add another run function, add your struct, add your run function, and you're that's, that's it.

So it really makes your code a lot simpler and makes it easier to contribute to and a bunch of, bunch of valuable aspects of it.

So how it'll work is let's make our, our, we'll probably have a default honeypot HTTP pot.

Why is this angry?

Ah, there, now it's good. We'll probably have a default HTTP pot.

And then all we need to do is call our address is going to be honeypots .honeypot.

We're going to get an address.

It's going to be the empty string. Right?

Yes. And then port is going to be 8080. It's very angry about something about this package.

And then we'll just call run and pass it in the honeypot here.

Missing return statement at the end of line 24.

That is very reasonable. And honeypots.go.

This is also a function that we should have a return statement for.

So there's something a little funky with my code here.

Not enough arguments, return nil. Perfect.

So this needs to return the error here. And we need to pointer, this needs to be a pointer.

So we can do, instantiate it like so.

And we can do run. And it should run. Yep. Should run a little HTTP server.

So we've got it working. Doesn't do anything. However, we've done a lot of setting up the environment, which is pretty neat and really valuable in the long-term.

What I'd like to do, I want to clean this up. So all of, I'm going to clean, do a little more cleaning this up and make sure it gets put on GitHub.

Check back here in about five minutes, and you should see HoneypotD with our contribution from today.

And next week, I'm going to want to add MySQL. I'm going to start wanting to add other servers in a really easy way.

So make sure you join me and thanks for watching this week.

Thumbnail image for video "Hacker Time"

Hacker Time
Join Evan Johnson each week for the latest security news, programming tutorials, and more!
Watch more episodes