<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <atom:link href="https://mileshuynh.duckdns.org/rss.xml" rel="self" type="application/rss+xml"/>
    <title>Miles Huynh</title>
    <link>https://mileshuynh.duckdns.org/</link>
    <description/>
    <lastBuildDate>Fri, 14 Aug 2026 15:23:54 +0700</lastBuildDate>
    <item>
      <title>Every command </title>
      <link>https://mileshuynh.duckdns.org/every-command-from-the-last-3-posts-in-one-place</link>
      <image/>
      <description>&lt;p&gt;A reference dump of every command from the honeypot, domain/HTTPS, and SSH-hardening posts — no narrative, just the commands, grouped by post.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;From: Building my first honeypot on AWS&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo apt install -y git python3-venv python3-dev libssl-dev libffi-dev build-essential
sudo adduser --disabled-password --gecos "" cowrie&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Cowrie itself was cloned and installed inside a &lt;code&gt;sudo su - cowrie&lt;/code&gt; session, so those exact clone/pip steps didn't survive in the ubuntu user's history — but the systemd unit that runs it did:)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo tee /etc/systemd/system/cowrie.service &amp;lt;&amp;lt; 'EOF'
[Unit]
Description=Cowrie SSH/telnet Honeypot
After=network.target
&lt;p&gt;[Service]
Type=forking
User=cowrie
Group=cowrie
WorkingDirectory=/home/cowrie/cowrie
Environment="PATH=/home/cowrie/cowrie/cowrie-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
ExecStart=/home/cowrie/cowrie/cowrie-env/bin/cowrie start
ExecStop=/home/cowrie/cowrie/cowrie-env/bin/cowrie stop
PIDFile=/home/cowrie/cowrie/var/run/cowrie.pid
Restart=on-failure&lt;/p&gt;
&lt;p&gt;[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable cowrie
sudo systemctl start cowrie
sudo systemctl status cowrie.service&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Quick log analysis, straight from the honeypot's own log file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;grep -c "New connection" var/log/cowrie/cowrie.log
grep -oP '(?&amp;lt;=,)[0-9]{1,3}(?:\.[0-9]{1,3}){3}(?=\])' var/log/cowrie/cowrie.log | sort | uniq -c | sort -rn | head -10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;From: Getting a real domain and real HTTPS&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo ss -tlnp | grep -E ':80|:443|:8080'
ps aux | grep -E 'nginx|apache2|php' | grep -v grep&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Edited &lt;code&gt;/etc/nginx/sites-enabled/default&lt;/code&gt;, changed &lt;code&gt;server_name _;&lt;/code&gt; to the real domain, then:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo nginx -t
sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d mileshuynh.duckdns.org&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;From: My real SSH port was just as exposed as my fake one&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo ss -tlnp | grep -E ':22|:2222'
sudo grep -i "^Port" /etc/ssh/sshd_config
sudo grep -iE "PasswordAuthentication|PermitRootLogin|PubkeyAuthentication" /etc/ssh/sshd_config
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd admin
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status fail2ban
sudo fail2ban-client status&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plus one change made entirely in the AWS console: the EC2 security group's port 22 rule, source changed from 0.0.0.0/0 to my own IP.&lt;/p&gt;</description>
      <pubDate>Fri, 14 Aug 2026 13:46:38 +0700</pubDate>
      <guid isPermaLink="false">85230d0c34073914af0c127f7037c445</guid>
    </item>
    <item>
      <title>Honeypot report: 2026-08-14</title>
      <link>https://mileshuynh.duckdns.org/honeypot-report-2026-08-14</link>
      <image/>
      <description>&lt;p&gt;2 connections hit the honeypot on 2026-08-14, from 1 unique IP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Top source IPs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-text"&gt;20.65.195.58  —  2 connections&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Auto-generated from the Cowrie session logs.&lt;/p&gt;</description>
      <pubDate>Fri, 14 Aug 2026 11:59:55 +0700</pubDate>
      <guid isPermaLink="false">71bd473f00f6a613e672dce15d496eaf</guid>
    </item>
    <item>
      <title>My real SSH port was just as exposed as my fake one</title>
      <link>https://mileshuynh.duckdns.org/appendix-every-command-i-ran-today</link>
      <image/>
      <description>&lt;p&gt;Went looking for the next thing to fix and found something dumber than expected: the box hosting my honeypot had a second, unintentional honeypot right next to it — my real SSH.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The discovery&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I'd assumed only Cowrie (port 2222) was exposed. A quick check said otherwise — port 22, the real sshd, was also open to 0.0.0.0/0. Any scanner had just as much access to my real login as to the fake one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Closing the real door&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Fixed it in the security group, not on the box — changed the port 22 source to "My IP." No risk of locking myself out, since editing a security group doesn't need SSH access. Password auth was already disabled, key-only login — the fix was about cutting attack surface, not plugging an active hole.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Locking /admin behind a second door&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Added HTTP Basic Auth in front of Bludit's login at the Nginx level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Almost made it worse&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nearly pointed fail2ban at the honeypot port too, out of a vague "more banning is safer" instinct — which would have defeated the entire point of Cowrie. Checked what fail2ban was actually watching: one jail, sshd, correctly scoped to the real port only.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I actually learned&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every port a security-group wizard opens is equally open to everyone, lure or not. Restricting a rule to "my IP" is safer than it sounds — fixing it wrong just means editing it again from a browser.&lt;/p&gt;
&lt;p&gt;Next up: what's landed in the Cowrie logs.&lt;/p&gt;</description>
      <pubDate>Thu, 13 Aug 2026 17:20:59 +0700</pubDate>
      <guid isPermaLink="false">056cfe5a70bc22a2d95b974d91260059</guid>
    </item>
    <item>
      <title>Getting a real domain and real HTTPS</title>
      <link>https://mileshuynh.duckdns.org/getting-a-real-domain-and-real-https</link>
      <image/>
      <description>&lt;p&gt;Next goal: stop serving this site off a bare IP and get it behind a real domain with real HTTPS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Free domain&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Used DuckDNS for a free subdomain, mileshuynh.duckdns.org. Gotcha: it auto-fills "current ip" with whatever machine is viewing the page, not the server — had to overwrite it manually.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nginx + Certbot&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Changed Nginx's catch-all server_name to the real domain, then ran Certbot with "redirect HTTP to HTTPS." Cert issued, deployed, auto-renewal scheduled — a surprisingly small amount of work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The mixed-content trap&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Switched to https:// and the page lost all styling. Bludit had the site's base URL cached as the old http://ip, so every asset request got blocked. Fixed by updating the URL setting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A brief AWS billing scare&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Watched the cost tick from $0.16 to $0.21 in a day, briefly panicked. Turned out I'm on AWS's credit-based free plan — everything draws from a $100 credit that comfortably outlasts the plan's window.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I actually learned&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;"Free" domain and HTTPS are each about 10 minutes once you know the gotchas. Mixed content errors are unusually self-explanatory. AWS billing looks scarier than it is.&lt;/p&gt;
&lt;p&gt;Next up: back to the honeypot, see what's landed in the logs.&lt;/p&gt;</description>
      <pubDate>Thu, 13 Aug 2026 16:37:36 +0700</pubDate>
      <guid isPermaLink="false">0887d00d976f27d396a1975f1bcb3f32</guid>
    </item>
    <item>
      <title>Building my first honeypot on AWS</title>
      <link>https://mileshuynh.duckdns.org/building-my-first-honeypot-on-aws</link>
      <image>https://mileshuynh.duckdns.org/bl-content/uploads/pages/f23c5844c7f0c5c7af1664d5ff4f8ee6/yeiferr-computer-4795762-1-.jpg</image>
      <description>&lt;p&gt;I've spent most of my time in IT support handling tickets, MFA resets, and onboarding — not touching cloud infrastructure directly. Today's goal: launch a real AWS server, put something live, and see what actually happens to it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Launching the instance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Picked the simplest starting point — a t3.micro running Ubuntu, free-tier eligible, connecting straight from the browser through EC2 Instance Connect. No key pair, no prior setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Putting something live&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nginx first, to prove I could serve something. Then a hand-written personal page, deployed by pasting into nano over SSH — small, but the first server I've ever owned end to end.&lt;/p&gt;
&lt;p&gt;Then I got curious who else was watching. Any public IP gets scanned constantly. Instead of ignoring it, I set up Cowrie — a fake SSH server on port 2222 that logs every command an attacker tries. Opened the port to the world, and within a few hours the first scanner found it: connected, grabbed the banner, disconnected in 34 milliseconds. No login attempt, no commands. Just reconnaissance — the internet doing what it always does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I actually learned&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Launching a real EC2 instance is a lot less scary than it sounds. A public IP gets attention within hours, not days. Logging is the whole point of a honeypot — the fake shell is just bait, the log file is the actual value.&lt;/p&gt;
&lt;p&gt;Next up: a real domain and HTTPS, then writing up whatever the honeypot picks up.&lt;/p&gt;</description>
      <pubDate>Wed, 12 Aug 2026 16:32:55 +0700</pubDate>
      <guid isPermaLink="false">f23c5844c7f0c5c7af1664d5ff4f8ee6</guid>
    </item>
  </channel>
</rss>
