目录
写在开头
本篇博客是根据红队笔记大佬的视频进行打靶,本次靶机依然是vulnhub上的prime,本文详述了提权的思路,从获得初始立足点www-data的shell开始,最终提权为root的过程。本文核心利用了OpenSSL的解密过程。前述的模糊测试及wfuzz工具的使用、文件包含漏洞利用、wordpress CMS代码执行的过程见我的上一篇博客:
红队打靶:Prime1详细打靶思路之模糊测试+内核提权(vulnhub)
上一篇博客的提权使用了内核提权。利用了老版本linux内核的漏洞,虽然提权过程并不复杂,但这种方式并不“优雅”,并不推荐大家作为首选。利用内核提权是很暴力的,容易导致系统服务的中断/重启,被系统管理员发现。因此,本文使用其他方式,涉及知识点包括find命令寻找备份、md5哈希生成、OpenSSL加解密的参数设定、bash脚本的编写等。详细思路见红队比较大佬的视频:
「红队笔记」靶机精讲:Prime1 - 提权的另一种解法,彻底搞懂OpenSSL解密渗透提权,超强思路版。_哔哩哔哩_bilibili
prime是vulnhub中的一台用于OSCP考试练习的的靶机,链接见:
靶机下载链接见:
https://download.vulnhub.com/prime/Prime_Series_Level-1.rar
特别注意,本文是从拿到www-data的shell开始的:
下面我们就开始提权的过程。
第一步:enc查找与破解
拿到www-data的shell之后,应该先查看自身权限:
sudo –l
发现www-data能够以root权限执行/home/saket/enc这个东西,那么我们cd /home/saket之后,看看enc是个啥
cd /home/saket
ls -liah
果然有个enc,而且是个可执行文件,既然他说能够在无密码的前提下以root权限运行,那我们在此目录sudo执行试试。
sudo ./enc
发现需要输入密码,那我们随便输入一个aaa试试,如上图,应该是失败了。此处应该是需要寻找密码,因此我们在整个系统中查找有没有备份信息,可能会泄露enc的密码信息。这也是打靶的常规思路,当发现登录或执行命令时需要密码,而我们此时不知道密码,可以在系统中寻找是否有信息泄露的位置,从而得到密码。根据经验,存放密码的地方可能是系统的备份,也可能管理员直接起名为password/passwd这样类似的名称,我们先在根目录开始寻找名称中存在backup字符的文件,命令如下:
find / -name "*backup*"
其中/表示从根目录开始搜索,-name表示以文件名作为匹配,"*backup*"表示匹配字符串中包含backup的文件。运行结果如下:
信息非常多,而且有好多都报错Permission denied(权限不允许),这种信息是没意义的,干脆把他丢弃掉,用2>/dev/null过滤:
find / -name "*backup*" 2>/dev/null
结果依旧有很多,我们应当选择最有可能泄露密码的位置。搜索结果中有很多在/usr/share/help目录下,help是帮助,应该不会泄露这些密码,另外有关内核的.ko文件也不会是。使用此命令发现第一个查找的结果就是/var/backups,感觉很有可能,那我们试试看。进入目录/var/backups,看看里面有什么:
里面还真有两个文件passwd.bak和shadow.bak。我们试试能不能查看,结果很可惜,权限不够,没法读:
那说不定其他目录也有备份,再找找吧。回看刚才find命令的找到的文件,最底下有个/opt/backup,那我们再看看:
进入目录/opt/backup,经过一系列的翻找,发现server_database目录下有个名为backup_pass的文件:
那我们查看backup_pass试试:
cat backup_pass
你说巧不巧,找到了!告诉我们enc的密码就是backup_password ,再回到/home/saket执行enc试试,输入密码backup_password 结果如下:
成功了!enc执行之后显示了一个good。
第二步:md5格式生成
就这?我辛辛苦苦找到了enc的密码,就是为了听你夸我一句good?那他肯定是干了点啥东西。先看看当前目录/home/saket有啥变化:
原来是运行enc之后,会吐出两个文件,enc.txt和key.txt,我们分别看看,先看enc.txt
nzE+iKr82Kh8BOQg0k/LViTZJup+9DReAsXd/PCtFZP5FHM7WtJ9Nz1NmqMi9G0i7rGIvhK2jRcGnFyWDT9MLoJvY1gZKI2xsUuS3nJ/n3T1Pe//4kKId+B3wfDW/TgqX6Hg/kUj8JO08wGe9JxtOEJ6XJA3cO/cSna9v3YVf/ssHTbXkb+bFgY7WLdHJyvF6lD/wfpY2ZnA1787ajtm+/aWWVMxDOwKuqIT1ZZ0Nw4=
感觉像一串乱码,也可能是一段密文。另外由于这个密文很长,估计是使用了某种方式对字符串进行了加密,并不是将较短的密码使用加密算法加密成定长的密文。再看看key.txt
I know you are the fan of ippsec.
So convert string "ippsec" into md5 hash and use it to gain yourself in your real form.
结果就两句话,直译:我知道你说ippsec的粉丝,那就将ippsec转换为md5的哈希,以获得你自己的真实形式。什么是自己的真实形式?先不管了,总之先把这个ippsec转化为md5哈希,命令为:
echo –n 'ippsec' | md5sum
加密结果为:
366a74cb3c959de17d61db30591c39d1
使用-n是为了去掉结尾的换行符,意思就是,如果不使用-n,那么相当于对”ippsec/n”进行了md5哈希(不是我们本意),这是完全不同的结果,如下图:
这个可以用指令man echo查看帮助,可以看到-n的作用就是不输出结尾换行符
我们已经得到了hash值,是366a74cb3c959de17d61db30591c39d1。当然,也可以更优雅的直接得到:
echo -n 'ippsec' | md5sum | awk -F ' ' '{print $1;}'
awk是对字符串进行处理的一个工具,awk -F ' ' '{print $1;}'意思是以空格为分割,打印其中第一个部分,这样就会只输出366a74cb3c959de17d61db30591c39d1 后面的‘-’不会输出。
这样我们就得到了密钥366a74cb3c959de17d61db30591c39d1。
第三步:OpenSSL解密参数确定
接下来综合enc,key.txt的信息,可以推断出,这是要我们对密文enc.txt使用密钥OpenSSL进行解密。这是经验。我们可以看一下openssl的帮助
openssl –h
这有一大堆标准命令和加密方式,标准命令中有enc,如果要想解密,我们必须要知道加密方式才行。这里我们采用的命令应该就是enc了,那么加密方式是啥呢?又有哪些参数呢?我们先看看enc命令的相关参数吧:
openssl enc –h
这里关于OpenSSL有一大堆参数,我们这里要解密,要用到-d,另外enc.txt看起来相似base64编码的,那么我们还有使用-a,当然用-base64也行,还要使用密钥key,参数-K,可是有个问题,-K后参数的说明他写到,需要Raw key,in hex 意思是需要16进制的格式,我们刚才得到的md5应该没有转换为这个形式,因此需要转化为16进制形式。
转换为16进制格式需要使用工具od,我们查看帮助od --help。
首先是输出格式-A,默认会输出片偏移offset的长度,这里我们不需要,因此选择None,参数为-A n。然后是16进制格式,我们要指定单字节单位十六进制数,参数为-t x1,具体情况可查看帮助,我就不在博客中赘述了。将ippsec的md5值转换为单字节单位的十六进制格式命令如下:
echo -n 'ippsec' | md5sum | awk -F ' ' '{print $1;}' |od -A n -t x1
od前面的语句是用于生成没有空格的'ippsec'的md5值,然后使用od 进行16进制转换。这样生成的结果如下:
使用此命令输出结果最后还有一个由换行符转换而来的空字符0a,我们不想要这个,干脆前面就把换行符干掉使用tr –d ‘\n’去掉换行符(-d是删除delete的意思):
echo -n 'ippsec' | md5sum | awk -F ' ' '{print $1;}' | tr -d '\n' | od -A n -t x1
继续进行处理,我们想把这个结果放在一行显示,同时去掉空格,再用tr –d 依次干掉换行和空格就好了,命令为:
echo -n 'ippsec' | md5sum | awk -F ' ' '{print $1;}' | tr -d '\n' | od -A n -t x1| tr -d '\n' | tr -d ' '
最终结果为3336366137346362336339353964653137643631646233303539316333396431。这就是openssl解密过程中-K后面的参数,即密钥的16进制形式。下面我们就可以构造对enc.txt进行OpenSSL解密的命令,完整命令为:
echo "nzE+iKr82Kh8BOQg0k/LViTZJup+9DReAsXd/PCtFZP5FHM7WtJ9Nz1NmqMi9G0i7rGIvhK2jRcGnFyWDT9MLoJvY1gZKI2xsUuS3nJ/n3T1Pe//4kKId+B3wfDW/TgqX6Hg/kUj8JO08wGe9JxtOEJ6XJA3cO/cSna9v3YVf/ssHTbXkb+bFgY7WLdHJyvF6lD/wfpY2ZnA1787ajtm+/aWWVMxDOwKuqIT1ZZ0Nw4=" | openssl enc -d -a -cipher -K 3336366137346362336339353964653137643631646233303539316333396431
这一段参数非常长,echo后面引号内的内容就是enc.txt中的密文,使用OpenSSL enc进行解密,-d是进行解密,-a意思是base64解码(也可以直接用-base64),-K后面接参数密钥raw的16进制hex形式,关键就在于-cipher应该替换为解密的算法,前面我们查看openssl enc的帮助的时候。我们看到了许多加密算法:
这么多可能的加密方式,我怎么知道这个OpenSSL是用哪个方式进行加密的呢?如果对密文的形式有了解的话,或许可以将加解密方式的范围缩小。但是对于我这种啥也不会的小白,似乎只能一个一个去尝试,把-cipher的位置依次换成这么多加解密方式。不过手工去尝试费时费力,不如想办法使用脚本。
第四步:OpenSSL解密(bash脚本)
上一步说我们要想办法枚举所有的加密方式的可能。那么最好就是写一个bash脚本,依次遍历每个加密方式,带入OpenSSL的解密命令执行,看看哪个能成功解密出明文。既然要使用脚本进行遍历,我们首先要创建一个文件,把这个openssl –h的内容关于加密算法的内容复制到一个文件中。干脆起名为CipherTypeRaw(之后要对这个文件进行遍历),去掉其中无关的行,结果如下(就是vim和复制操作,不赘述了):
有这么多种可能,我们对CypherTypeRaw进行处理,保证每个字符串独占一行,这样方便遍历。首先把所有空格替换为换行符,这样就可以保证每一项字符串独占一行,使用gsub()函数用于将空格替换为换行符,完整命令如下:
awk '{gsub(" ","\n");print}' CypherTypeRaw
由于空格非常多,因此替换后的换行符也特别多,我们最好是把这些换行符都去掉,最简便的方法就是先排序sort,保证所有非空行聚集在一起,再使用uniq,直接过滤掉重复的行,这样处理之后只剩一个空行了:
awk '{gsub(" ","\n");print}' CypherTypeRaw | sort | uniq
我们把这个结果输入到文件,起名为CipherTypes,这就是处理好的文件,命令如下:
awk '{gsub(" ","\n");print}' CypherTypeRaw | sort | uniq > CypherTypes
最后这个CypherTypes文件有99行,含第一行空行和98种加密方式。回到刚刚的OpenSSL解密命令中,现在我们可以构造bash脚本,写一个for循环,将CipherTypes中的每一行替换为上述命令中的-cipher,bash脚本如下:
for cipher in $(cat CypherTypes); do echo "nzE+iKr82Kh8BOQg0k/LViTZJup+9DReAsXd/PCtFZP5FHM7WtJ9Nz1NmqMi9G0i7rGIvhK2jRcGnFyWDT9MLoJvY1gZKI2xsUuS3nJ/n3T1Pe//4kKId+B3wfDW/TgqX6Hg/kUj8JO08wGe9JxtOEJ6XJA3cO/cSna9v3YVf/ssHTbXkb+bFgY7WLdHJyvF6lD/wfpY2ZnA1787ajtm+/aWWVMxDOwKuqIT1ZZ0Nw4=" | openssl enc -d -a -$cipher -K 3336366137346362336339353964653137643631646233303539316333396431 ;done
运行结果:
确实看到了几行文字,到这里其实已经解密完成了,但我们还是想知道到底是哪一种解密方式成功解密,因此我们重新构造命令输出每次遍历的字符串(即解密方式)。由于使用其他解密方式都会报错,我们将报错信息丢弃2>/dev/null ,完整的命令为:
for cipher in $(cat CypherTypes); do echo "nzE+iKr82Kh8BOQg0k/LViTZJup+9DReAsXd/PCtFZP5FHM7WtJ9Nz1NmqMi9G0i7rGIvhK2jRcGnFyWDT9MLoJvY1gZKI2xsUuS3nJ/n3T1Pe//4kKId+B3wfDW/TgqX6Hg/kUj8JO08wGe9JxtOEJ6XJA3cO/cSna9v3YVf/ssHTbXkb+bFgY7WLdHJyvF6lD/wfpY2ZnA1787ajtm+/aWWVMxDOwKuqIT1ZZ0Nw4=" | openssl enc -d -a -$cipher -K 3336366137346362336339353964653137643631646233303539316333396431 2>/dev/null;echo $cipher;done
可以更清晰的看到,可以用于解密的字符串,即加密方式为aes-256-ecb,因此,我们只要执行如下命令即可得到单纯的解密结果:
echo "nzE+iKr82Kh8BOQg0k/LViTZJup+9DReAsXd/PCtFZP5FHM7WtJ9Nz1NmqMi9G0i7rGIvhK2jRcGnFyWDT9MLoJvY1gZKI2xsUuS3nJ/n3T1Pe//4kKId+B3wfDW/TgqX6Hg/kUj8JO08wGe9JxtOEJ6XJA3cO/cSna9v3YVf/ssHTbXkb+bFgY7WLdHJyvF6lD/wfpY2ZnA1787ajtm+/aWWVMxDOwKuqIT1ZZ0Nw4=" | openssl enc -d -a -aes-256-ecb -K 3336366137346362336339353964653137643631646233303539316333396431
这句话意思就是我们得到了saket的密码为tribute_to_ippsec,很可能就是saket账户ssh登录的密码。同时还有一个名为Victor的落款,不知道能不能用上。
第五步:提权
用ssh登录saket账户,并输入密码tribute_to_ippsec
登录成功了,我们还是用看看自己是谁:
果然是saket,ip地址也没问题,这个shell交互性差,还是用python拿到交互性更好的shell,先用dpkg -l | grep python看看有没有python,发现有,然后可以用如下命令拿到交互性更好的shell:
python -c "import pty;pty.spawn('/bin/bash')"
既然想提权,那我们就先知道自己当前是啥权限:
sudo -l
提示我们,可以无密码的形式以root运行/home/victor/undefeated_victor,那咱就运行试试:
sudo /home/victor/undefeated_victor
结果说,找不到/tmp/challenge这个文件,还给了一句提示:如果你能够打败我,就先挑战站在你面前的你。这啥意思啊?挑衅呢?既然他说找不到/tmp/challenge这个文件,那咱们就去tmp目录下看看:
确实是没有名为challenge的文件呀,以root运行/home/victor/undefeated_victor会去运行/tmp/challenge,如果challenge中包含提权的指令,那么一旦运行就可以提权了,现在既然没有这个challenge文件,那咱就创建一个。尝试了一下,没有vim,那咱们就用echo的方式创建challenge并追加命令:
echo '#!/bin/bash' > challenge
echo '/bin/bash' >> challenge
好了,challenge的提权文件已经创建好,接下来我们只要执行/home/victor/undefeated_victor应该就可以提权了:
是我得意忘形了,提示没有权限,应该是刚创建的challenge文件没有执行权限。现在给challenge这个文件添加执行权限:
chmod +x challenge
这样应该就可以执行了,再次执行/home/victor/undefeated_victor,即可提权成功
sudo /home/victor/undefeated_victor
成功拿到了root权限,在/root目录下可以看到root.txt,这个就是flag。至此打靶完成。
总结与思考
本文涉及知识点包括find命令寻找备份、md5哈希生成、OpenSSL加解密的参数设定、bash脚本的编写等。真是没想到,仅提权一个思路就可以总结这么多过程,不过本文篇幅较长还是因为对bash脚本已经一些字符串处理工具awk/od/tr等进行了详述。如果熟悉这个过程的话,渗透测试的过程应该不会很长。本文主要总结了OpenSSL解密的过程,至于为什么想到OpenSSL,主要还是根据enc和key.txt的提示,需要一定的经验才可。
本文的思路相比于上一篇博客总结使用内核漏洞提权的方式,更为优雅,不容易造成系统的崩溃和服务的终止,是更推荐的思路。最后总结一下OpenSSL解密和提权全过程的思路:
enc查找与破解:拿到www-data权限后,提示我们去寻找enc,结果发现要执行enc需要密码,使用find命令查找备份,最后成功找到了enc的密码,执行后生成key.txt和enc.txt
md5格式生成:key.txt文档中提示我们生成ippsec的md5值,使用md5sum进行生成即可。
OpenSSL解密参数的确定:查看OpenSSL enc -h帮助可知,我们需要使用的参数包括-d解密,-a使用base64解码,-K [16进制单字节密钥],-解密方式。其中的解密方式我们无法确定。
OpenSSL解密:构造CipherTypes文件,每个解密方式独占一行,构造bash脚本通过for循环遍历CipherTypes判断解密方式,并成功解密,获得saket的ssh密码。
提权:常规思路,寻找以root权限执行的文件challenge,在对应的文件中加入获得shell的指令,执行即可提权。
有关prime靶场的打靶就总结完毕了,没想到总结的篇幅还挺长的。虽然没有多少读者看这个红队打靶的专栏,但我还是想记录记录自己学习渗透测试的历程,也希望对得起未来的自己的。如果有读到这里的读者恳请多多点赞支持。有关打靶的问题也可以在评论区指出。后续我可能会继续打靶,也可能会总结一些渗透测试的技巧等等,希望读者多多支持。