খোলা রেখে ভুলে যাওয়া পোর্ট সার্ভারে ঢোকার ক্লাসিক পথ: পাবলিক ঠিকানায় ডেটাবেস, ডিবাগ ড্যাশবোর্ড, এমন কন্টেইনার যা কেউ না চাইলেও একটি পোর্ট প্রকাশ করেছে। দুটি কমান্ড আর একটি ফাঁদ জানলে পরীক্ষায় এক মিনিট লাগে। নিচের সবকিছু আমরা আমাদের ইমেজ থেকে তৈরি নতুন Ubuntu 24.04 সার্ভারে করেছি এবং দ্বিতীয় একটি মেশিন থেকে স্ক্যান করেছি, তাই আউটপুট হুবহু তাই যা আপনি নিজের সার্ভারে দেখবেন।
1. কী শুনছে
কমান্ডটি ss। অক্ষরগুলোর মানে TCP, UDP, শুনতে থাকা সকেট, পোর্ট নম্বর আর প্রসেসের নাম:
sudo ss -tulpn
নতুন সার্ভারে এটি ছয়টি লাইন ছাপে:
Netid State Local Address:Port Process
udp UNCONN 127.0.0.54:53 systemd-resolve
udp UNCONN 127.0.0.53%lo:53 systemd-resolve
tcp LISTEN 127.0.0.54:53 systemd-resolve
tcp LISTEN 127.0.0.53%lo:53 systemd-resolve
tcp LISTEN 0.0.0.0:22 sshd
tcp LISTEN [::]:22 sshd
গুরুত্বপূর্ণ কলাম Local Address। এটি বলে কে সংযোগ করতে পারে:
| ঠিকানা | কে পৌঁছাতে পারে |
|---|---|
127.0.0.1:… বা 127.0.0.53 | শুধু এই সার্ভারের প্রোগ্রাম |
0.0.0.0:… | IPv4 দিয়ে যে কেউ, যদি না ফায়ারওয়াল আটকায় |
[::]:… | IPv6 দিয়ে যে কেউ (সাধারণত IPv4-ও) |
10.0.0.5:… (নির্দিষ্ট ঠিকানা) | যে কেউ যে ওই ঠিকানায় পৌঁছাতে পারে |
অর্থাৎ নতুন সার্ভার বাইরে শুধু একটি জিনিস খোলে: পোর্ট 22-এ SSH, IPv4 ও IPv6-এ। 127.0.0.53-এর DNS রিজলভার ব্যক্তিগত।
ইন্টারনেট যা দেখতে পারে শুধু তা দেখাতে loopback ঠিকানাগুলো বাদ দিন:
sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'
প্রতিটি ইনস্টলের পরে এটি চালান। আমরা nginx, Docker আর একটি ছোট Python অ্যাপ ইনস্টল করেছিলাম, তালিকা 2 লাইন থেকে 10 লাইনে দাঁড়াল, যার মধ্যে ছিল 0.0.0.0:8081-এ docker-proxy এবং একটি এলোমেলো localhost পোর্টে containerd-এর সকেট।
2. কোন প্রসেস পোর্ট দখল করেছে
পোর্ট ব্যস্ত থাকলে এবং কে নিয়েছে জানতে চাইলে:
sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'
পড়তে সবচেয়ে সহজ lsof। nginx-এর জন্য এটি root হিসেবে একটি মাস্টার প্রসেস আর www-data হিসেবে একটি worker দেখাল, দুটোই *:80-এ, IPv4 ও IPv6-এর জন্য। fuser শুধু PID ছাপে, স্ক্রিপ্টে কাজে লাগে। পোর্ট খালি করতে হলে PID মারার বদলে সার্ভিস থামান, নইলে systemd আবার চালু করবে: sudo systemctl stop nginx।
3. ইন্টারনেট কী দেখে
ss সার্ভারের দৃষ্টিভঙ্গি দেখায়। ইন্টারনেটের দৃষ্টিভঙ্গি আলাদা হতে পারে, কারণ মাঝে ফায়ারওয়াল আছে বা সার্ভিসটি 127.0.0.1-এ বাঁধা। আসল ছবি দেখতে সার্ভারটি অন্য মেশিন থেকে স্ক্যান করুন, আপনার ল্যাপটপ বা দ্বিতীয় সার্ভার থেকে। টুলটি nmap (apt install nmap, অথবা Windows ও macOS-এ nmap.org-এর ইনস্টলার)।
nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip
প্রথম রূপটি সবচেয়ে প্রচলিত 1,000 পোর্ট, দ্বিতীয়টি সব 65,535 আর তৃতীয়টি একটি তালিকা পরীক্ষা করে। আমাদের নতুন সার্ভারে, কোনো ফায়ারওয়ালের আগে:
Not shown: 999 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
Nmap done: 1 IP address (1 host up) scanned in 6.83 seconds
সব 65,535 পোর্টের পূর্ণ স্ক্যানে 8.9 সেকেন্ড লেগেছে এবং একই একমাত্র পোর্ট পাওয়া গেছে। বন্ধ পোর্ট সঙ্গে সঙ্গে reset দিয়ে উত্তর দেয়, তাই সেগুলোর স্ক্যান দ্রুত।
তিনটি অবস্থা গুরুত্বপূর্ণ:
- open: কোনো প্রোগ্রাম সংযোগ গ্রহণ করেছে। এটাই আপনার আক্রমণের পৃষ্ঠ।
- closed: সার্ভার উত্তর দিয়েছে যে সেখানে কিছু শুনছে না। নিরাপদ, তবে নিশ্চিত করে যে সার্ভারটি আছে এবং কী চালাচ্ছে না।
- filtered: কোনো উত্তর নেই। ফায়ারওয়াল প্যাকেট ফেলে দিয়েছে। স্ক্যানার জানতে পারে না পেছনে কোনো সার্ভিস আছে কি না।
কিছু ইনস্টল না করে একটি পোর্টের জন্য nc -zv সার্ভার-ip 443 উত্তরে succeeded বা refused দেয়, আর ফিল্টার করা পোর্টে টাইমআউট পর্যন্ত আটকে থাকে। UDP-এর জন্য nmap-এ -sU যোগ করুন এবং অপেক্ষার জন্য প্রস্তুত থাকুন; আমাদের সার্ভারে তিনটি প্রচলিত UDP পোর্ট 53, 123 ও 161 সবই closed ছিল।
NAT প্ল্যানের জন্য একটি নোট: ইন্টারনেট থেকে শুধু সেই SSH পোর্টে পৌঁছানো যায় যা আমরা আপনার জন্য ফরোয়ার্ড করেছি। শেয়ার করা ঠিকানার স্ক্যান আমাদের প্রান্ত দেখায়, আপনার সার্ভার নয়, আর বাকি পোর্টে কিছু শুনলেও তা নাগালের বাইরে। নিজস্ব IPv4 ঠিকানার প্ল্যানে প্রতিটি খোলা পোর্ট আপনি নিজে সামলান।
4. যা লাগবে না তা বন্ধ করুন
তিনটি উপায়, সেরা থেকে সবচেয়ে বিস্তৃত পর্যন্ত।
localhost-এ বাঁধুন। কোনো সার্ভিস যদি শুধু সার্ভারের প্রোগ্রাম ব্যবহার করে, তবে সেটিকে 127.0.0.1-এ শুনতে দিন। আমরা একটি ছোট ওয়েব অ্যাপ --bind 127.0.0.1 8080 দিয়ে চালিয়েছিলাম: ss সেটিকে 127.0.0.1:8080-এ দেখাল, আর বাইরে থেকে nmap জানাল 8080/tcp closed। ডেটাবেসের জন্য এটাই সঠিক ডিফল্ট: Ubuntu-তে Redis, MySQL ও PostgreSQL শুরু থেকেই localhost-এ শোনে, আর Redis ও MySQL-এর জন্য আমাদের গাইড সেটাই রাখে।
সার্ভিস থামান। sudo systemctl disable --now নাম শ্রোতাকে চিরতরে সরিয়ে দেয়। ss দিয়ে যাচাই করুন যে সেটি চলে গেছে।
ফায়ারওয়াল চালু করুন। আগে SSH, তারপর আপনি যা পরিবেশন করেন তার অনুমতি দিন, তারপর চালু করুন:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose
বাইরে থেকে স্ক্যান পুরোপুরি বদলে গেল:
Not shown: 997 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8081/tcp open blackice-icecap
Nmap done: 1 IP address (1 host up) scanned in 10.18 seconds
অনুমতি ছাড়া প্রতিটি পোর্ট closed থেকে filtered হয়ে গেল, আর 65,535 পোর্টের পূর্ণ স্ক্যানে এখন 8.9-এর বদলে 110 সেকেন্ড লাগল। স্ক্যানারের জন্য প্রতি পোর্টে বেশি সময়, আপনার সার্ভার সম্পর্কে কম তথ্য। আমাদের UFW গাইড রেট লিমিট, একটি IP-কে অনুমতি দেওয়া ও IPv6 নিয়ে আলোচনা করে।
কিন্তু তৃতীয় লাইনটি দেখুন।
5. Docker-এর চমক
ফায়ারওয়াল চালু থাকা অবস্থায় এবং অনুমতি দেওয়ার কোনো নিয়ম ছাড়াই পোর্ট 8081 খোলা রইল। পোর্টটি সেই কন্টেইনারের, যেটি আমরা docker run -p 8081:80 nginx:alpine দিয়ে চালিয়েছিলাম। Docker কার্নেলের ফায়ারওয়ালে নিজের নিয়ম যোগ করে, আর সেগুলো ufw-এর নিয়মের আগে মূল্যায়িত হয়। আমাদের সার্ভারে এটি যে নিয়ম লিখল:
-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80
পোর্ট 8081-এর প্রতিটি প্যাকেট ufw কিছু বলার আগেই কন্টেইনারে পাঠিয়ে দেওয়া হয়। -p বা ports: এন্ট্রি থাকা প্রতিটি কন্টেইনার এটাই করে, আর ss সৎভাবে এটিকে 0.0.0.0:8081-এ docker-proxy হিসেবে দেখায়।
সমাধান হল শুধু localhost-এ প্রকাশ করা:
docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine
Compose-এ ports:-এর নিচে "127.0.0.1:8081:80" লিখুন। পরিবর্তনের পরে ss দেখাল 127.0.0.1:8081, Docker-এর নিয়মে -d 127.0.0.1/32 যোগ হল, আর বাইরে থেকে স্ক্যান জানাল 8081/tcp filtered। পাবলিক দিকের জন্য HTTPS সহ nginx-কে reverse proxy হিসেবে সামনে রাখুন, যাতে সার্ভারে শুধু পোর্ট 22, 80 ও 443 খোলা থাকে।
প্রতিটি পরিবর্তনের পরে চেকলিস্ট
sudo ss -tulpn:0.0.0.0বা[::]থাকা প্রতিটি লাইন কি এমন কিছু যা আপনি খুলতে চেয়েছিলেন?- ল্যাপটপ থেকে
nmap সার্ভার-ip: খোলা পোর্ট কি মিলছে? - পাবলিক ঠিকানায় ডেটাবেস, ক্যাশ বা অ্যাডমিন প্যানেল: আজই
127.0.0.1-এ বা ফায়ারওয়ালের পেছনে সরান। - Docker-এর প্রতিটি
ports:এন্ট্রি: পাবলিক ওয়েব পোর্ট না হলে কি127.0.0.1:দিয়ে শুরু হয়? - SSH সবার জন্য খোলা: fail2ban বা শুধু কী দিয়ে লগইন যোগ করুন।
Windows Server-এ একই পরীক্ষা Get-NetTCPConnection -State Listen, আর নিয়মগুলো থাকে Windows Firewall-এ। $3-এর Nano থেকে শুরু করে প্রতিটি Linux প্ল্যানের নিজস্ব IPv4 ঠিকানাসহ একটি সংস্করণ আছে, আর সেখানে আপনি ss-এ যা দেখেন, গোটা বিশ্বও তাই দেখে, শুধু আপনার ফায়ারওয়াল যা আটকায় তা বাদে।
মন্তব্য
এখনো কোনো মন্তব্য নেই। প্রথম হোন।