Category Archives: Networking

Pfsense + UDM + VLANs: The perfect home network

A couple weeks ago I did a mayor reconfiguration on my home network, I migrated from a single flat insecure network in where any device was able to talk to any other to a more secure design in where the network is segmented (IoT devices, guests, home lab, etc) and where I control who has access to what resources via firewall rules and other tools.

My original home network consisted of a single Google Wifi router, if you are interested the device it’s limited but will get the job done. However I wanted to learn more about networking and in particular how to configure a couple of monitoring tools, network packet inspection, security, firewall rules, etc. So I started looking at networking appliances that will let me do more advanced configurations and I quickly found about Pfsense (Protectli Vault) so I got one.

Additionally, as a birthday gift from @perrohunter, I got The Dream Machine from Ubiquiti (usually you will use one or the other) so I had two routers now. 

I had to integrate them together but I faced a couple of issues during the process to the point where I got locked out from the network and I had to reset the devices multiple times, either the Pfsense or the UDM would work but not both of them at the same time but after some time it’s finally working so I decided to document the process in case it helps someone in the future.

Designing the network

The main goal was to have a clear separation between IoT devices, guest devices and my home devices so i came out with this design.

Disclaimer: I’m a security software engineer but I know a thing or two about networking, if you see something wrong or do you think this design can be improved in any way please let me know.

As you can see, I’m putting the Pfsense at the edge of the network so I have full control over the traffic. I’m using the UDM as an access point only because most of the routing and DNS resolution will be done by Pfsense. The home network consists of 3 VLANs.

IoT network VLAN 30

All my smart lights, roomba, smart locks, cameras will be here, these devices cannot communicate to the other networks or connect to the Internet. Only wireless devices will connect to this network.

Guests network VLAN 50

Occasionally I get visitors at my place, guests can connect to this network and enjoy access to the Internet however devices here will not be able to talk to devices on the IoT nor the LAN network. TODO: I want to put some rules in place so guests’ devices are fully isolated from each other. Only wireless devices will connect to this network.


This is the main network and it’s a combination between wired and wireless devices, my work stations, laptops, mobile devices, home servers, smart tv, gaming consoles, etc. These are devices that I trust and most of them have static IPs and dns names.


I’m not going to explain in detail how to do the initial configuration for the Pfsense or the UDM, there are thousands of videos and tutorials that can guide you through that, instead I’ll focus on the parts I struggled the most and the “hacks” I applied to make this work.

Pfsense setup

These devices will usually come with two ports, WAN and LAN. I had to connect the Ethernet cable from the modem to the WAN port (also called an interface) and that will be enough for the device to talk to the internet in most cases. After that, during the initial configuration Pfsense asked me to configure the LAN interface, there I chose the network IP, IP range, etc In my case I selected as my network IP range.

You can tweak and do some more advanced configurations under Services > DHCP Server > LAN

DHCP got configured automatically for this interface so I didn’t worry about it.

After that I grabbed another Ethernet cable and connected it into the Pfsense LAN port and the UDM WAN port.

The Dream Machine (UDM) setup

Here is where the issues begin, I connected the Ethernet cable to the UDM, the app guided my through the initial configuration, then I created the initial Wireless network and everything seemed to work fine however after looking at Status > DHCP Leases on my Pfsense I could not see any of my wireless devices, that was weird.

I logged in into the Dream Router management console and I could see my wireless network, the default network and the wan interface. I also could see all my connected devices, however the assigned IP addresses were in the range not the So I had some idea about what was happening, UDM had its own DHCP server and was assigning the IP addresses itself.

I start trying many different things, some of them were:

  • Disabling DHCP in the default network of the UDM didn’t work.
  • Changing the network range in the default network of the UDM to didn’t work, UDM was complaining that the range conflicts with the IP assigned to it (
  • Created an additional network on the range I wanted didn’t work, devices from here were not able to see the Pfsense.

I tried many more things and after a couple weekends of trial and error I found the winning combination of steps, this is probably the most important part of this article.

  • Disconnect the Ethernet cable from the UDM WAN port, this cause the UDM to lose the IP assigned by the Pfsense
  • Change the default network configuration in the UDM to use the network, this network will overlap with the network in Pfsense but it’s ok, also set DHCP Mode to none.
  • In the UDM go to Internet > default WAN and select manual configuration, here I’m setting the primary DNS server as (Pfsense) and IPv4 configuration has to be as follow

Here I’m telling UDM the next hop will be at (Pfsense), also I want the UDM to use the static IP, and the subnet mask will be which ended being the “hack” that allow me to use the 10.13.37.x range on the default network

Finally plug the Ethernet cable again into the UDM but this time into any of the LAN ports not the WAN (the little world icon), avoid the WAN port seriously!.

The reason why I want the default network in the UDM to be an overlap of the network in the Pfsense was because otherwise I would lose access to the UDM management console, I’m still trying to figure out why is that but my guess is even if the UDM is accessible from the Pfsense network on IP address when I try to go to there (if the default network range is configured to be on UDM) it won’t let me in because of some validation on UDM, to avoid this I ended creating a dedicated wireless network just to recover access (after getting locked out multiple times).

Using the above configuration my devices in the range are able to talk to Pfsense ( and also the UDM ( and finally I’m able to see and control my devices from the Pfsense as well.


Network interfaces

The main network is working fine now what? I started creating additional VLANs and firewall rules for the guests and the IoT networks. On the Pfsense I went to  Interfaces > Assignments > VLANs and added the two VLANs. It’s very important to select LAN as the parent interface because all the traffic is going to come from that port.

For no particular reason I chose tag 30 for the IoT VLAN and tag 50 for the guest VLAN, don’t forget to assign the new VLANs to the LAN interface and create the new networks.

To be consistent I decided the guests network range will be and the IoT will follow

DHCP Server

Now it was time to configure the DHCP server for the new networks, I went to Services > DHCP Server and made sure the enable DHCP box was checked, additionally I configured the assignable IP range. I did this for both networks.

Firewall rules

According to my original design the guests and IoT network have to be isolated from everything else and in particular the IoT devices should not have any access to the Internet, let’s do that very quickly by configuring firewall rules on Pfsense (Firewall > Rules).

These are the rules applied to the IoT_VLAN, here I’m telling Pfsense to block any incoming connection from the IoT network to the home or guests network, I’m also blocking the access to the Pfsense management console itself on port 8443 and 3000. This firewall by default will block any egress traffic in the network and because I’m not saying otherwise this network will not have access to the Internet.

The guest firewall rules are pretty much the same with the exception that I will allow users to access the Internet (see the last rule).

The Dream Machine

At this point I was done with the Pfsense part but I was missing one last import piece, configuring the access method for the IoT and guests devices so for that I had to return to the UDM management console and create a couple of wireless and network configurations.

Guest Network

I created the new guest network configuration, most of the default values were ok but I had to pay special attention to the VLAN ID section, this one has to match to the one I configured on Pfsense (tag 50). Also is very important to set DHCP Mode to None

I created the Wifi network and told UDM to use the guest network, all packets will be marked (tag 50) and managed by the guest VLAN.

IoT Network

I repeated the previous steps but this time for the IoT network, I proceeded to create the network, added the right VLAN (tag 30) and disabled DHCP, then configured the wifi network as well.


Once everything is configured the way I wanted I tested by connecting a couple of devices to the IoT network and monitored the traffic with the help of ntopng (maybe I will write a blogpost about it in the future), there I confirmed there was not a single request to a remote address.


Designing a network is one of the most fun things you can do in IT. The main reason for me to get the Pfsense was because I wanted to learn more about networking and have hands-on experience with several networking and security tools. VLANs, Firewall rules, DHCP, DNS, packet inspection etc are good skills for a security engineer but these are only the tip of the iceberg for a network engineer.

Weak TLS cipher suites

HTTP and HTTPS are well known Internet protocols that don’t require any introduction. The other day at work as part of a daily security scan one of our servers got tagged as using weak cipher suites during TLS negotiation. In this quick post I’ll explain what a weak cipher suite means and how to fix it.

There are many tools out there to check if you are following the security best practices when it comes to SSL/TLS server configuration (supported versions, accepted cipher suites, certificate transparency, expiration, etc.) but one of my favorites is and drwetter/ is easy to use, you just have to enter a Hostname and the website will analyze all possible TLS configuration and calculate a score for you, this tool will also tell you what you can do to improve that score.

There are many TLS protocol versions: 1.0, 1.1, 1.2, 1.3. The first two are considered insecure and should not be used so I will focus on 1.2 and 1.3 only.
In my case was complaining about weak cipher suites were supported for TLS 1.2:

The above report is showing ECDHE-RSA-AES256-SHA384E and ECDHE-RSA-AES256-SHA as weak cipher suites.

First let’s clarify a couple of things, according to Wikipedia:

Cipher suite: A set of algorithms that help secure a network connection.

So a weak cipher suite will be algorithms with known vulnerabilities that can be used by attackers to downgrade connections or other nefarious things.

Fixing this is very easy and will require changing a line or two on the server configuration, deploying the changes and then testing again using

Of course, the above only applies if you know exactly what you are doing, otherwise it will take you many attempts and you are going to waste precious time.

Reproduce and fix the issue locally

Suppose you have the same issue I had, because this issue was reported on an Nginx Server now the task is to reproduce the issue locally and come up with a fix. With modern technologies like docker containers it’s very easy to run a local Nginx server, the only thing you need is a copy of the nginx.conf, to run a docker container the command will be:

docker run --name mynginx -v ./public.pem:/etc/nginx/public.pem -v ./private.pem:/etc/nginx/private.pem -v ./nginx.conf:/etc/nginx/nginx.conf:ro -p 1337:443 --rm nginx

The above command is telling docker to run an Nginx container; binding the local port 1337 to the container port 443 and also mounting the public.pem (public key), private.pem (private key) and nginx.conf (the server configuration) files inside the container.

The nginx.conf looks like this:

    server {
        listen 443 ssl;
        ssl_certificate /etc/nginx/public.pem;
        ssl_certificate_key /etc/nginx/private.pem;
        ssl_protocols TLSv1.3 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
        ssl_ciphers EECDH+AESGCM:EECDH+AES256:EECDH+CHACHA20;
        ssl_session_cache shared:TLS:2m;
        ssl_buffer_size 4k;
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;

You can test the server is working fine with a simple curl command:

curl https://localhost:1337/ -v -k
*   Trying
* Connected to localhost ( port 1337 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Server: nginx
< Date: Sun, 15 May 2022 23:14:23 GMT
< Content-Type: text/html
< Content-Length: 146
< Connection: keep-alive
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
<head><title>404 Not Found</title></head>
<center><h1>404 Not Found</h1></center>
* Connection #0 to host localhost left intact

The next step is to reproduce the report from but that will involve somehow exposing our local Nginx server to the internet and that’s time consuming. Fortunately there’s an amazing open source tool that will help you to run all these TLS tests locally.

drwetter/ is a tool for testing TLS/SSL encryption anywhere on any port and the best part is that runs on a container too, go to your terminal again and run the following command:

docker run --rm -ti --net=host drwetter/ localhost:1337

The above command will run the drwetter/ container, the –rm flag will automatically delete the container once it’s done running (keep your system nice and clean), -ti means interactive mode and –net=host will allow the container to use the parent host network namespace.

After a couple of seconds you will see a similar result as in the website, something like this:

Testing server’s cipher preferences.

Hexcode  Cipher Suite Name (OpenSSL)       KeyExch.   Encryption  Bits     Cipher Suite Name (IANA/RFC)                        
TLSv1.2 (server order)                                                                                                         
 xc030   ECDHE-RSA-AES256-GCM-SHA384       ECDH 521   AESGCM      256      TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384               
 xc02f   ECDHE-RSA-AES128-GCM-SHA256       ECDH 521   AESGCM      128      TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256               
 xc028   ECDHE-RSA-AES256-SHA384           ECDH 521   AES         256      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384               
 xc014   ECDHE-RSA-AES256-SHA              ECDH 521   AES         256      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA                  
 xcca8   ECDHE-RSA-CHACHA20-POLY1305       ECDH 521   ChaCha20    256      TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256         
TLSv1.3 (server order)                                        
 x1302   TLS_AES_256_GCM_SHA384            ECDH 256   AESGCM      256      TLS_AES_256_GCM_SHA384                              
 x1303   TLS_CHACHA20_POLY1305_SHA256      ECDH 256   ChaCha20    256      TLS_CHACHA20_POLY1305_SHA256                        
 x1301   TLS_AES_128_GCM_SHA256            ECDH 256   AESGCM      128      TLS_AES_128_GCM_SHA256

Even on this test we see the weak cipher suites (ECDHE-RSA-AES256-SHA384 and ECDHE-RSA-AES256-SHA).

Great, now you are able to fully reproduce the issue locally and test as many times as you want until you have the perfect configuration. It’s time to do the actual fix.

Open the nginx.conf file one more time and locate the line that starts with ssl_ciphers and just add !ECDHE-RSA-AES256-SHA384:!ECDHE-RSA-AES256-SHA at the end, ie:

 server {
        listen 443 ssl;
        ssl_certificate /etc/nginx/public.pem;
        ssl_certificate_key /etc/nginx/private.pem;
        ssl_protocols TLSv1.3 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
        ssl_session_cache shared:TLS:2m;
        ssl_buffer_size 4k;
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;

If you run the Nginx container with the new configuration and then run the drwetter/ test again this time you will see no weak cipher suites anymore.

TLSv1.2 (server order)                                                                                                         
 xc030   ECDHE-RSA-AES256-GCM-SHA384       ECDH 521   AESGCM      256      TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384              
 xc02f   ECDHE-RSA-AES128-GCM-SHA256       ECDH 521   AESGCM      128      TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256              
 xcca8   ECDHE-RSA-CHACHA20-POLY1305       ECDH 521   ChaCha20    256      TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256        
TLSv1.3 (server order)          
 x1302   TLS_AES_256_GCM_SHA384            ECDH 256   AESGCM      256      TLS_AES_256_GCM_SHA384                              
 x1303   TLS_CHACHA20_POLY1305_SHA256      ECDH 256   ChaCha20    256      TLS_CHACHA20_POLY1305_SHA256                        
 x1301   TLS_AES_128_GCM_SHA256            ECDH 256   AESGCM      128      TLS_AES_128_GCM_SHA256


Congratulations, you just fixed your first security engineer issue and now you can push the fix to production. In general when it comes to fixing any kind of problem in tech it is better to start by reproducing the issue locally and work on a fix from there (of course this is debatable if you are facing an issue that only happens in a specific environment). SSL/TLS  and cipher suites are one of those technologies that you have to learn by heart or at least have a very good understanding if you want to work in application security, but not only that, once you understand it it will completely change the way you approach problems and debug security applications .

Happy hacking.

10 things you should be doing if you care about security in your Tech Startup

I’ve been working in the startup world as a Software Engineer for a little bit more than two years now, as most of you already know, I’m very passionate about information security so I decided to create a list of things you can do to protect your technology Startup (most of them for free).

SPOILER ALERT: This publication is not going to be your typical article about which crypto cipher is better to use, IDS comparisons or talking about specific DLP products , instead, I would like to cover 10 actions (more like advices) you can take if you value your product, your data, your employees and if you want to protect your Startup in general.

So if you are the CEO, CTO, some high executive or a decision maker in your Startup this information is for you.

1: Enforce the use of password managers

Everything starts with a password, literally, sign-in into your computer is one of the first thing most of you do every morning. Whether email clients, social networks, instant messaging apps, or online banking all this requires the user to provide a password in order to access the service so it’s natural for common users to want to think in a password only 1 time and then reuse it across multiple services.

Reusing passwords (even with small variations) it’s a bad thing because once your password is guessed/stolen it can be used to compromise all your other accounts (facebook, twitter, instagram, gmail, outlook, etc), attackers can automate the process using hacking tools such as credmap: The Credential Mapper.

So how do we prevent employees passwords to be guessed (dictionary attack) while at the same time make sure they are using strong and unique passwords on each one of their accounts? The answer is Password Managers.

Password Managers allow you to have one master password (for choosing a strong master password please refer to my talk How to create secure passwords) and then generate all the others you need based on a secure configuration such as secret length, character types, etc.

So the next time you want to access your favorite social network you just need to copy and paste the password, that also prevents your password for being stolen in case of a keylogger attack. You don’t want your community manager accounts to be stolen right?

There are a lot of good solutions out there for managing your passwords, some of them are free and open-source and some others requires you to buy a license, I personally use KeePass which is free, here is a list of the most popular password managers, doesn’t matter which one you want to choose but go ahead and start using password managers if you are not doing it yet!

2: Use multi-factor authentication if possible

The key of security is to add multiple layers of protection so in case one of them fails the other ones handle the risk, in particular for protecting accounts we can suggest our employees to use 2 factor or multi-factor authentication every time they can, so if a data breach happen and the passwords are stolen and cracked, attackers are still unable to log into the accounts because they are missing the token generator.

Now a days most of the more popular services support multi-factor authentication using one time passwords, token generators (such as google authenticator) or even hardware authenticator devices.

Personally I use a Yubico authenticator key and I’m very happy with it 🙂 every time I need to access my accounts from a new IP address or an unrecognized browser, websites such as Facebook or Gmail will ask for my authentication key, that’s very helpful because even if my password is leaked/cracked or someone guess it, they still need the physical key to access the service. 

If you don’t have a budget or prefer not to spend money on this you still can enforce multi-factor authentication using these free apps (every employee can have a token generator right on his smartphone):

3: Choose a secure instant messaging application

Every organization use some kind of real time communication application (Slack, Microsoft Teams, etc) and sometimes employees need to share sensitive information between them, they do not realize the information is also being shared with the third-party service provider who can read it.

Fortunately, nowadays more and more services support security features such as end to end encryption which means all communications between devices are encrypted (each device has a public and a private key) and not even the service provider can read them because they don’t have the private keys.

Another cool feature is self-destruct messages, basically you can set a timer so messages only exists during a particular amount of time after being send and then are destroyed, very useful when you want to share sensitive data such as passwords.

Some free apps that include these features are:

4: Securing all Email communications

Email communications is an essential part in every organization, making it a very attractive vector for attackers, according to a new report from PhishMe, 91% of Cyberattacks start with a phishing email, so even if you have advanced network controls, deceiving your users is still easy.

Nowadays attackers have access to sophisticated phishing tools like SET (Social-Engineer Toolkit) or Gophish which they use to target your employees, they also have access to large repositories of open-source phishing tools they use to tune and adapt their attacks to specific people.

Most of this tools allow attackers to spoof corporate emails and trick your users into downloading malicious files into their systems and into your network, spotting spoofed email addresses is very difficult for common users however using security software like PGP (Pretty Good Privacy) & GPG can help you to mitigate the issue.

Enforcing the use of software such as GPG (GNU Privacy Guard) could help your startup in many ways, like verify the legitimacy of a received messages or encrypt an email content so only a specific user can read them.

You can verify if a message you receive is legit by using the public key of the sender (usually another employee in the organization), meaning: if the person that sent you the email also signed the message using his private key and that private key is associated with the public key you have, then you are guaranteed the message is coming from the right person.

I know this sounds a little bit confusing at the beginning, but the main idea is that every person in the company has a key pair, a public key and a private key, everybody exchanges their public keys while keep their private keys to themself, so when I want to send a message to Mr John Doe I write the message normally and then I proceed to sign it with my own secret key, optionally I can encrypt the message using the public key of John Doe, so the message can only be decrypted and read it by the private/secret key of John, finally John can use my public key to verify the signature I applied to the original message (the one I generated with my private key).

If you still don’t get it don’t worry about it, nowadays most email clients support PGP and the process for verifying and decrypting emails is automatically, there is also a chrome extension called FlowCrypt that I highly recommend!

This message was encrypted with my public key and then sent to me, not even google can read this.
The message decrypted on my browser via the FlowCrypt browser extension

5: Encrypting all your drives

Now we are introducing the concept endpoint protection and “data loss prevention“, in fact I think most of you already use some form of data encryption software, I’m not going to go deep into the details but encrypting your drives could protect your data in many cases, ie: someone steal a company hard drive and try to mount it in another computer to read the information.

If your employees are MacOS users, the operating system already come shipped with FileVault enabled by default, if they use Windows they can use BitLocker and if they use a modern Linux distribution (ie: Ubuntu) full disk encryption is also available.

Data encryption has pros and cons, but the benefits are superior from a privacy and security stand point so I highly recommend to use full disk encryption in all company devices if possible, also the solutions I mentioned above are all free, so you don’t need to spend any money on this one too in order to protect your employees.

6: Encourage secure coding best practices

Usually, when you start a new company then financial resources are limited and you need to be very careful with the people you hire, basically you want to have the best developers, people that are really good at whatever they do but also are wiling to learn and adapt to different situations, you want Rockstar developers.

Rockstars developers have the potential for learning anything, so feed them with the right content, Open Security Training contains great resources about different topics of security like Introduction to Secure Coding, the best part is, are you ready?, its all FREE! in fact this is how I have been learning about security all this years.

Besides Open Security Training there is also The Open Web Application Security Project (OWASP), which is also a good resource for starters so they can learn how to create secure web applications and also secure mobile apps.

Everybody can learn about Security these days, encourage your developers to do it (give them time and resources) and your team will become stronger!, here are some extra sources I had used in the past:

7: Consider hiring a security expert to join your team or an external security team

This advice is more for mature startups or executives who already have a budget to spend on cybersecurity, but it can also apply if you are a small startup and have some friends in the security community.

The idea is to have someone in your team that can give you advice and guidance on different security matters, ie: implementing a security plan for the software development process, do threat modeling in your organization, security infrastructure (IDS, IPS, firewalls, etc), security training, network protection or just make sure your employees are safe are just some examples of things your tech Startup needs from a security perspective.

Besides having your own security guy consider hiring an external security team too, having the security assessment of an external team allow you to simulate more realistic attacks to your organization so you can be more prepared when the real thing happen.

Here are some personal thoughts about security people:

  • Security people are different
  • We enjoy talking about security all the time
  • We want to get asked about how to protect X or Y technology
  • We enjoy challenges and puzzles
  • we enjoy to break stuff and tell you how to fix them.

8: Start a bug bounty program

Companies doesn’t like the idea of their product being hacked, personally I believe that way of thinking need to change because it’s a good thing to have a group of white hat hackers finding vulnerabilities in your software before the bad guys do it.

You can start a bug bounty program with a well defined scope so people can try to hack your product legally (you can even set some special environments for this), there are some guidelines regarding how much to pay depending on the type of vulnerability but if you are still a small startup you can also offer some “swag” like t-shirts or gadgets.

In return you get (most of the time) an army of high quality security researchers that will deliver good vulnerability reports, including how to fix your security issues, everybody wins 🙂

Some popular bug bounty platforms right now are:

9: Encourage a cybersecurity culture in the Startup

The success of the cybersecurity strategy in the organization depends pretty much on the people, you can not just spend a lot of money on security assets like Firewalls and Antivirus and expect everything to be magically safe, it’s not possible because people are always the weakest part in the chain. Security is like a game and everybody need to play including high executives like CEOs and CTOs.

In order to have a culture of cybersecurity organizations have tried different things through the years, even punishing their employees, which is not very effective because people end hating security policies. In general people tend to care about security only when affects them directly but they also like rewards so there is a “new” trend in the security community about using gamification in which basically you reward your employees when they have a responsible security behaviour.

Those action might include:

  • Employees getting rewards when reporting phishing emails
  • Escort people without badge outside the facilities
  • Report suspicious USB drives or hardware that should not be there to the IT/Security department.
  • Enforce people to lock their workstation when not using them by sending emails (using the unlocked account) about free donuts for the whole floor/department/team :p

The idea of all this is to be fun while at the same time the organization become more secure against external threats.

10: Be transparent about Security issues and data breaches

Your biggest fear became true, your Startup got hacked and your information is all over the Internet, If you followed all my advices chances are your sensitive information like passwords are encrypted, which is useless for the attackers, however you still have a moral (and in some places legal) duty, you need to notify your customers and employees about the data breach (according to GDPR you have 72 hours to report a personal data breach after it’s discovered) basically every minute you wait is a minute attackers can invest into cracking and recovering the information so it’s better to communicate the incident, so people can start acting accordingly (change passwords, cancel credit cards, etc).

If you decide to hide the breach and continue without doing anything eventually everybody is going to know about hack and your reputation will be irreversibly damaged (nobody will trust you anymore) so its better to be open with your customers an accept the failure, the shame will be momentary but you will do the right thing.

There is no such thing as a Silver bullet in Cybersecurity, It’s not a matter of if you are going to be hacked or not, it’s about when is going to happen and if your organization is going to be prepared, and this is true for all companies.

Some final thoughts

Security people are often seen as blockers in the organization but I assure you, they have good intentions so please listen to them. Security is hard to implement and even harder to maintain so if you are the CEO/CTO/[Person with authority] of the startup consider to join the security team so you can experience first hand the whole process 🙂

Finally, all these advices are based on my personal opinion (I’m just a security enthusiast) so if you think I should add something else please leave it in the comments.

Happy hacking 🙂

Docker 101 #1: Introducción a docker y los contenedores


Hola lectores, en los últimos 6 meses he tenido la oportunidad de estar desarrollando mi carrera en una de las empresas de tecnología más grandes que hay en México, he estado trabajando muy de cerca en temas de Cloud computing, virtualizacion, bare metal e IaaS en general.

Es por eso que he decidido que es una buena idea crear una serie de tutoriales sobre docker, herramienta que considero esencial para los desarrolladores hoy en día, sobre todo si te atrae el mundo del cloud computing :). Si no tienes conocimientos previos de docker no te preocupes, planeo escribir tutoriales desde cero y voy a ir explicando cosas un poco más complejas conforme vayamos avanzando.

Un poco de teoria

Cuando hablamos de docker hablamos de contenedores. Pero ¿Que es un contenedor?, seguramente podrás encontrar una definición más formal de lo que es, pero imagínate que un contenedor es una caja que contiene tu solución de software, y no solo eso, también contiene las dependencias necesarias para ejecutar tu aplicación, las dependencias pueden ser librerías, configuraciones especiales e incluso otras aplicación o servicios que necesites (como un servidor web, nginx, apache, tomcat, etc.), todas las dependencias y aplicaciones dentro de una imagen están organizadas mediante un concepto de layers (capas), de esa manera cuando modificas un contenedor (una imagen) solo actualizas un layer en específico.

La gran ventaja de los contenedores es que, a diferencia de las máquinas virtuales estos no tienen asignadas cuotas específicas de recursos del sistema host (memoria, cpu, storage, etc), cuentan con un sistema de archivos virtual que permite que los contenedores se ejecuten de forma independiente y separada de los procesos del sistema, de esta manera la memoria de un proceso del contenedor no interfiere con un proceso de la maquina donde es ejecutado.

Un contenedor solo incluye consigo la aplicación y sus dependencias lo que hace que las imágenes de docker sean bastante livianas.

Otro de los grandes beneficios que nos aportan los contenedores es la potabilidad, me refiero a que si tienes una aplicación y la quieres migrar a otro sistema (por ejemplo de desarrollo a producción) puedes creas una imagen de docker que incluya tu solución y ejecutarla en cualquier otro sistema teniendo la certeza de que va a “correr” pues la imagen contiene todas las dependencias necesarias. Existen técnicas para “comunicar” nuestra maquina host con los contenedores como el mapeo de puertos y directorios, eso lo veremos en los siguientes tutoriales.

Conceptos básicos

  • Docker: Tecnología de software para creación y administración de contenedores.
  • Docker image: Un sistema de archivos virtual que puede contener aplicaciones y dependencias.
  • Docker container: Una imagen de docker que está siendo ejecutada, una instancia de una imagen.
  • Dockerhub: Un repositorio que contiene muchísimas imágenes de docker listas para ser descargadas.
  • DockerFile: Un script que indica una serie de pasos para construir una imagen de docker.

Bien suficiente teoría, si quieres saber más a fondo sobre docker pueden visitar el sitio web o ir a la documentación oficial

Instalar docker

Lo primero que debemos hacer es instalar docker, dependiendo de tu sistema operativo es el instalador que utilizaras, descarga docker de la página oficial, si estas en Windows descarga el ejecutable y sigue el wizard (siguiente, siguiente, siguiente), en Mac OSX puedes descargar una imagen dmg y hacer lo mismo, en mi caso lo que tengo a la mano es un sistema Linux, Ubuntu para ser específico y para proceder con la instalacion lo hago de la siguiente forma:

$ sudo apt-get install

Sea cual sea tu sistema operativo, una vez hayas instalado docker para verificar que la herramienta está bien instalada abre una consola y escribe el comando docker

$ docker


Si el resultado es un output similar al de la imagen significa que instalaste docker correctamente, si por el contrario recibes algún mensaje que dice que el comando docker no existe esto se puede deber a varias razones pero principalmente si estas en Windows verifica que la ruta al binario de docker se encuentre definida en tus variables de entorno.

Docker contiene muchisimos comandos pero los más importantes, o al menos los que utilizaras más son:

  • $ docker run
  • $ docker images
  • $ docker build
  • $ docker pull
  • $ docker ps
  • $ docker start
  • $ docker stop
  • $ docker commit
  • $ docker attach

Conforme vayamos avanzando en los tutoriales iré explicando que hace cada uno de ellos

Nuestro primer contenedor

Estamos listos para crear nuestro primer contenedor, abrimos una consola y escribimos el siguiente comando:

$ sudo docker run hello-world

El comando anterior le dice a docker que ejecute una nueva instancia (un contenedor) de la imagen hello-world, primero busca en el repositorio local y si no la encuentra va al dockerhub y procede a con la descarga.


¿Observas la parte que dice Pull complete?:

Unable to find image ‘hello-world:latest’ locally
latest: Pulling from hello-world

264eca88cf85: Pull complete
f0cb9bdcaa69: Pull complete
Digest: sha256:548e9719abe62684ac7f01eea38cb5b0cf467cfe67c58b83fe87ba96674a4cdd
Status: Downloaded newer image for hello-world:latest

Ahi es donde docker está mostrando el progreso de la descarga y los layers de la image, el resultado final de ejecutar este contenedor es el mensaje que dice: Hello from Docker!

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:

For more examples and ideas, visit:

Si ejecutamos el comando docker images, obtendremos una lista de las imágenes que tenemos disponibles localmente, y claro ahí tenemos nuestra imagen hello-world

$ docker images


Ahora veremos uno de los conceptos importantes de docker, el sistema de archivos virtual, vamos a descargar y ejecutar una imagen docker de ubuntu con el comando:

$ sudo docker run ubuntu


Corroboramos que tenemos una nueva imagen almacenada localmente:

[email protected]:~$ sudo docker images
ubuntu latest 426844ebf7f7 2 weeks ago 127.1 MB
hello-world latest f0cb9bdcaa69 3 months ago 1.848 kB

Ya tenemos una imagen docker de ubuntu, ¿Pero cómo accedemos a ella? ¿Cómo la utilizamos?, podemos utilizar el siguiente comando para acceder al contenedor en tiempo de ejecución utilizando una shell interactiva:

$ sudo docker run -t -i ubuntu /bin/bash

Cuando el contenedor este corriendo podrás navegar su sistema de archivos como lo harías normalmente en Linux, incluso si estas corriendo docker desde una maquina con Windows podrás ver que el sistema de archivos es de Linux, aquí es donde puedes empezar a considerar la opción de dejar atrás Cygwin y comenzar a utilizar un contenedor de ubuntu con todas las herramientas que necesites.


Para salir del contenedor utiliza el comando exit, como si terminaras una sesión remota de ssh.

Un punto importante a recalcar es que los contenedores no son persistentes, si creas un archivo dentro del contenedor la siguiente vez que lo ejecutes no existirá, posteriormente veremos cómo podemos solucionar eso. Por el momento quiero que entiendas los conceptos básicos de los contenedores en docker, como descargar imágenes y lanzarlas, los comandos básicos, etc.

Al inicio mencionaba el dockerhub, el repositorio público de donde puedes descargar miles de imágenes de docker, te invito a explorarlo e instalar las que más te gusten:


Servidor web nginx utilizando docker

Para terminar el tutorial mostrare rápidamente como podemos ejecutar un servidor web utilizando docker, como mencionaba, el dockerhub tiene miles de imágenes públicas y muchas comunidades de software libre están creando versiones “contenerizadas” de sus soluciones, en este caso el servidor web nginx, lo primero que debemos hacer es descargar la imagen de nginx para docker

$ sudo docker pull nginx


Ejecutamos docker images para verificar que se descargó correctamente:

[email protected]:~$ sudo docker images
ubuntu latest 426844ebf7f7 2 weeks ago 127.1 MB
nginx latest 4c0e7e3661d2 2 weeks ago 181.4 MB
hello-world latest f0cb9bdcaa69 3 months ago 1.848 kB

Ahora para lanzar el contenedor utilizaremos el comando:

$ sudo docker run –name nginx-server1 -p 80:80 nginx


  • El comando docker run especifica que queremos correr un contenedor
  • El parametro –name nos permite definir un nombre único y amigable para esa instancia
  • El parametro -p nos permite mapear puertos entre el sistema operativo y los servicios que corren dentro del contenedor
  • Al final especificamos el nombre de la imagen de la cual queremos crear el contenedor, nginx en este caso


Incluso podemos abrir una segunda terminal y ejecutar el siguiente comando para lanzar un segundo servidor web contenerizado pero en un puerto diferente:

$ sudo docker run –name nginx-server2 -p 8080:80 nginx


Al lanzar cada una de las imágenes de nginx habrás notado que la consola se queda “ocupada” corriendo el contenedor, en el siguiente tutorial mostrare como evitar eso, finalmente para detener la ejecución del contenedor presiona ctrl+c

Si ejecutas el comando docker ps -a podras ver todas los contenedores que hemos creado hasta el momento, la mayoria no estara en ejecucion y puede ser eliminado utilizando docker rm [CONTAINER ID]


Si haz entendido bien los conceptos básicos ya te imaginaras el potencial de docker y hacia donde iré en los siguientes tutoriales :).

Saludos y happy hacking.

Solución al reto Capture The Flag de #CPMX6


Otro año, otro campus party al que asisto. En esta ocasión me di tiempo de asistir a varias conferencias y workshops que se impartieron durante el evento (y no solo pasármela en la zona gamer :p), además, al igual que en el evento pasado también estuve participando en el reto de seguridad que fue organizado por el Instituto Tecnológico Superior de Atlixco.

El wargame estuvo muy divertido (horas y horas de diversión) y me ayudo a conocer a mas colegas de la seguridad informática durante el evento, bueno sin mas preámbulo comienzo a explicar en que consistía cada uno de los retos y como fue que llegue a la solución.

Reto #1

Comenzando con lo básico, en el reto uno nos daban la IP donde había alojada una pagina web, la pagina tenia varias pestañas y la URL de cada una de las secciones tenia una estructura como la siguiente:


Jugando un poco con el parámetro file vemos que el sitio tiene una vulnerabilidad de Local File Inclusión. Utilizando la herramienta que desarrollo mi amigo @lightOS para explotar este tipo de vulnerabilidad es posible automatizar el proceso y obtener archivos importantes del servidor, por ejemplo:



Sin embargo, el reto es mas sencillo que eso, en el archivo robots.txt (corrimos un dirbuster al sitio web) vimos que hay un archivo llamado dir.txt, revisando su contenido nos encontramos:

$ ls -l

secreto.txt, un archivo interesante, entonces aprovechamos el Local File Inclusion que teníamos y cargamos este archivo.



67d71184adf4b700d5cadce0c9bfdcc7e91d01cb <- esta es la bandera del reto 🙂

Reto #2

El segundo reto nos daba como pista “DNS record types” junto con un dominio, si es la primera vez que escuchan de record types en el siguiente enlace podrán encontrar mas información

Entendiendo un poco mas sobre el tema comenzamos a hacer lookup a los distintos records hasta que llegamos al record TXT y encontramos la solución.


4db055f7386c6bb8a14b5883417a4b61 <- es la bandera de este reto

Reto #3

El reto numero 3 es bastante interesante, al inicio nos dan una captura de paquetes, un archivo .pcapng que procedemos a visualizar con wireshark (si no han escuchado de el o no saben utilizarlo ahora es el momento


Como podemos observar hay partes de la lectura que están cifradas (ahí se ve una negociación TLS), por suerte entre los archivos que nos daban también venia una llave privada (llave.pem) que nos servirá para descifrar esas partes. En Wireshark nos vamos al menú Edit > Preferences y en la siguiente ventana del lado derecho seleccionamos Protocol > SSL


Damos clic en RSA keys list y agregamos una nueva llave, nos pedirá algunos datos como dirección IP, puerto, protocolo y la llave privada (llave.pem), haciendo un análisis de lo que teníamos anteriormente:

En la captura tenemos dos direcciones IP:

  • (dirección local)
  • (dirección remota a la que nos estamos comunicando)

De igual forma, viendo la captura, sabemos que la comunicación con la maquina remota fue atreves de ftp utilizando el puerto 21 (por default) por lo tanto escribimos esos datos y adjuntamos la llave privada como se muestra en la siguiente imagen.



Damos ok a las ventanas y Wireshark nos debería de mostrar el trafico descifrado. Para analizar mas rápido vamos a pasar la captura a un archivo de texto, File > Print. Seleccionamos Plaint Text y Output to file.


Abrimos el archivo generado con nuestro editor de texto favorito y empezamos a buscar por cadenas interesantes como password, pass, secret, etc


La bandera de este reto es: ZXASDF727fa2raSFP!FRA-,aSF

Reto #4

El reto cuatro era facil y consistía en un reto criptográfico, al principio nos daban una cadena de texto que parecía no tener sentido y en mi experiencia la mayoría de los retos de este tipo son cifrados caesar. Con la ayuda de google buscamos un sitio para resolver este tipo de cifrados de sustitución por desplazamiento

Introducimos el texto cifrado y obtenemos la respuesta 🙂


Mas sabe el diablo por viejo que por diablo <- esta es la bandera del reto

Reto #5

Tip: la bandera es el md5 del contenido del archivo zip.

El reto nos da un archivo comprimido en formato zip, que tiene la particularidad que al descomprimirlo nos genera otro archivo zip, y después otro y otro mas, parecería nunca acabar, lo primero que hice fue abrir el archivo con un editor hexadecimal solo para corroborar lo que ya sabíamos.


Del lado derecho podemos ver los nombres de los archivos que se van generado:,,,, etc. (son bastantes) así que lo mas fácil es realizar un script para descomprimir todo lo que haya que descomprimir recursivamente xd, yo utilice un comando en bash.

$ while [ "`find . -type f -name ‘*.zip’ | wc -l`" -gt 0 ]; do find -type f -name "*.zip" -exec unzip — ‘{}’ \; -exec rm — ‘{}’ \;; done

Al final del ultimo Zip nos encontramos con un archivo de texto llamado flag.txt, calculamos su hash md5 y obtenemos la bandera 🙂

$ md5sum flag.txt
da44354d0de702b12934235a51094813 flag.txt

da44354d0de702b12934235a51094813 <- es la bandera del reto (el hash)

Reto #6

El reto 6 nos dio bastante dolor de cabeza a los participantes, a pesar de que su solución era bastante sencilla, en el reto nos daban una dirección IP y se nos pedía utilizar nmap (para escaneo de puertos y servicios) y Hydra para realizar ataques de fuerza bruta, hubo bastante confusión puesto que a aparentemente el servidor solo tenia corriendo un servicio de ssh y fue lo que intente atacar.

El servidor ssh no soportaba autenticación mediante usuario y contraseña por lo que termine creando script en bash, python, etc y probando diferentes tipos de exploits sin éxito :(. Me di cuenta que el primer escaneo que realice no fue un barrido completo de puertos, así que volví a escanear nuevamente esta vez asegurándome de revisar todos los puertos.

$ nmap –sV –p- –version-all –max-retries 1–d IP

333/tcp open ftp vsftpd 2.0.8 or later

Service detection performed. Please report any incorrect results at .
# Nmap done at Fri Jul 24 18:08:31 2015 — 1 IP address (1 host up) scanned in 6.26 seconds

Y ahora si encontramos que en el puerto 333 había un servidor de ftp corriendo.
Empezamos a analizar el servicio, tratamos de conectarnos y vemos como responde.

Intentando conectarse con el usuario admin

$ ftp admin @ 333
Connected to
220 Welcome to FTP service.
331 Please specify the password.
530 Login incorrect.
ftp: Login failed
ftp> exit
221 Goodbye.

Intentando conectarse con el usuario root

$ ftp root @ 333
Connected to
220 Welcome to FTP service.
530 Permission denied.
ftp: Login failed
ftp> exit
221 Goodbye.

El usuario admin parece ser valido (vean como las respuestas son diferentes), pero no tenemos la contraseña, utilizaremos hydra y un buen diccionario, al final y después de un par de horas obtuvimos la contraseña 🙂

$ hydra -t 1 -l admin -P default_pass_for_services_unhash.txt -vV -s 333 ftp


La bandera de esto reto era x.x: 12345678 (máximum trolling)

Reto #7

Otro reto bastante sencillo, aquí nos dan una foto y se nos pide encontrar la marca del dispositivo con el que fue tomado la fotografía.

Utilizamos cualquier extractor de metadatos online y obtenemos que la foto fue tomada con una dispositivo Huawei


La bandera del reto es: Huawei

Reto #8

En el reto 8 nos dan un archivo .iv que podemos crackear utilizando aircrack-ng, para quien no sepa aircrack es un software incluido en la distribución de seguridad Kali que sirve para crackear redes inalámbricas

En nuestro kali utilizamos aircrack-ng para procesar el archivo .iv del reto:

$ aircrack-ng captura.iv


Y obtenemos la contraseña de la red inalámbrica que también es la solución al reto
12345 <- es la bandera de este reto

Reto #9

El ultimo reto del capture the flag consistía en explotar una vulnerabilidad de inyección SQL y obtener la contraseña en texto plano del administrador del sitio. El reto, al inicio nos presenta un sitio web con un catalogo de películas, podemos consultar las películas de un director en especifico con una URL similar a la siguiente:


Esta claro que si queremos inyectar comandos SQL tendremos que empezar por el parámetro idDirector y para hacerlo de una forma mas rápida y automática utilizaremos la herramienta sqlmap que viene instalada en nuestro Kali.

$ sqlmap –url= –level=1 –risk=3 –all


La herramienta nos hace un dump de la tabla de usuarios y vemos que los passwords son almacenados no en texto plano sino cifrados (probablemente en md5), también observamos que la tabla contiene un campo de salt y un valor que muy seguramente fue utilizado para calcular el hash de la contraseña.

Pues manos a la obra (o mas bien dicho, al teclado), el reto nos pide encontrar la contraseña del usuario maria (que es el administrador del sitio), podemos hacer rápidamente un script para intentar crackear el hash.

$salt = "WDUOPALD6N";
$hash = "fa38084963f74741ea1184963fa2cd91";

$handle = fopen("pass2.txt", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {

$line = str_replace("\n", "", $line);

if(md5($salt.$line) == $hash || md5($line.$salt) == $hash)
echo $line . " OK! \n";
} else {
echo $line . ":" . md5($salt.$line) . " Nop\n";

} else {
echo "file error \n";


Lo que hace nuestro script es, con la ayuda de un diccionario de 2 millones de contraseñas populares, intentar encontrar cual es el texto plano concatenado al valor salt del hash que obtenemos, para cada contraseña de nuestro diccionario calculamos

  • salt + contraseña = hash
  • Contraseña + salt = hash

Y revisamos si tenemos alguna coincidencia.


Afortunadamente la contraseña en texto plano se encontraba en nuestro diccionario y la pudimos encontrar 🙂

La bandera del reto final era: passw0rd1 (era la contraseña numero 795975 en nuestro diccionario)


Nos vemos el siguiente año.
Happy hacking 🙂