2019“黄鹤杯”全国总决赛 WEB Write Up ——yzddMr6

前言

三天赶了两场比赛

黄鹤杯体验极佳 ,比某500空间好到不知哪里去了

web就两个题,一开始就打穿了

于是本菜鸡就开始了划水运动hhhhh

web1

web1是个thinkphp5

扫一下目录有个www.zip

打开后看到源码

image

有注册 有登录按钮,然后看源码的意思是让你成为admin用户,然后可以得到一个hint来进行下一步

image

Userinfo.php

<?php

namespace app\index\controller;

use think\Controller;
use think\Db;
use think\Request;
use think\Validate;

class Userinfo extends Controller
{
    public function user(Request $request)
    {
        $session = $request->session('username');
        if($session === 'admin')
        {
            return view('user',['info'=>'welcome admin!!','flag'=>'This is your hint:   <br>hint{xxxxxxxxxx}']);
        }
        else{
            return view('user',['info'=>"hello {$session}",'flag'=>'This is your hint:   <br>flag{}<br>maybe the admin have some hints:)']);
        }
    }

    public function change()
    {
        return view();
    }

    public function changeinfo(Request $request)
    {
        $dbuser ='*****';
        $dbpass ='*****';
        $dbname ="study";
        $host = 'localhost';
        @error_reporting(0);
        @$con = mysqli_connect($host,$dbuser,$dbpass,$con);
        // Check connection
        if (!$con)
        {
            echo "Failed to connect to MySQL: " . mysqli_error();
        }
        @mysqli_select_db($con,$dbname) or die ( "Unable to connect to the database: $dbname");


        $post = $request->post();
        $username = $request->session('username');
        $pass = $post['password'];
        $curr_pass = $post['current_password'];
        $validate = Validate::make(['password'=>'min:3|confirm']);
        $status = $validate->check($post);
        if($status){
            if (preg_match("/select|update|delete|insert|into|set|;|between|regexp|like|rlike|=|substr|mid|ascii|join|char|order|count|rand|floor|group|extractvalue|updatexml|exp|concat|outfile|\(|\)/i", $curr_pass) || preg_match("/select|update|delete|insert|into|set|;|between|regexp|like|rlike|=|substr|mid|ascii|join|char|order|count|rand|floor|group|extractvalue|updatexml|exp|concat|outfile|\(|\)/i", $pass)) {
            $this->success('go out!! hacker','/xinan/public/index/index/index');
            } else {
                $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
                $res = mysqli_query($con,$sql) or die('You tried to be smart, Try harder!!!! :( ');
                $row = mysqli_affected_rows();
                if($row = 1){
                    $this->success('修改成功啦','/xinan/public/index/login/index');
                }else {
                    $this->error('修改失败,请联系管理员');
                }

            $this->error($validate->getError());
        }
    }
}

但是过滤了一大堆关键字,防止注入

然后翻翻目录发现两个有意思的地方

  1. 根目录下有个shell.php
  2. 出题人的log没删。。。

shell.php

 <?php 
echo "这个是内网的操作页面,只允许内网人员使用,get_cmd";
echo "<br />";
if($_SERVER["REMOTE_ADDR"] === "127.0.0.1") 
{ 
    
     
       @eval(system($_GET["cmd"]));
     
} 
else 
      { 
        echo "您的ip是".$_SERVER["REMOTE_ADDR"]."<hr/>"."不是我们的内网机器"."<hr/>"."这是一台内网机器,只接受本机请求"."<hr/>"; 
        return false; 
      } 

是个cmd一句话,但是必须127.0.0.1访问

猜想可能hint就是个ssrf

然后看log

image

翻翻里面有没有什么有意思的东西

想起了国赛决赛直接把payload放log里了hhhh

前面的都没啥意义,就是出题人调试的过程

然后看到了这个

image

印证猜想,就是给你一个可以ssrf的地址让你去打shell.php

访问了一下100e8a82eea1ef8416e585433fd8462e.php结果是404

说明可能实际题目中改了名字,这时候就必须要拿到hint才可以得到真实地址

然后正在看他是怎么才能成admin的时候,平台发了一个公告

image

猜想是怕有些战队扫不到源码备份故意放的水

下载下来后还真是

但是!!!

主办方直接把真实环境的源码给发出来了

image

阿伟死了

直接找到55ceedfbc97b0a81277a55506c34af36.php

<?php 
   echo 'please get $url';

    $url = $_GET['url'] ?? false; 
    if($url)  
    { 
    $a = preg_match("/gopher/i", $url);
        if ($a==0)
        { 
            
            echo "<br />";
            echo "操作错误,你是我们的内网人员吗";
            exit(); 
            
        } 

            $ch = curl_init(); 
            curl_setopt($ch, CURLOPT_URL, $_GET["url"]); 
            curl_setopt($ch, CURLOPT_HEADER, 0); 
            curl_exec($ch); 
            curl_close($ch); 

     } 

?>

果然是个ssrf,直接跳过了成为admin这一步

payload中还必须有gopher这个单词,这是明晃晃的暗示啊hhhh

然后就是生成gopher二进制流来打

然而实际中被坑的不轻。。。

开始一直是400,不知道为什么

image

心里想着woc这tm还有幺蛾子

被坑了好久。。。然后没办法让队友看,给他说了思路后队友直接一个payload打过去flag出来了

image

喵喵喵??? 为毛我一直400

最后才发现一个坑人的地方

就是你在编码payload的时候要用burp的右键send to decoder

而不能用复制粘贴,否则格式会乱,阿帕奇就400

但是我一直都是这么打的啊。。。不知道为什么今天会出错

结果拿了四血,菜鸡大哭.jpg

web2

web2是个smarty的模版注入

这是拿到shell后看的源码

image

就是两个接口 一个获取ip,一个获取xff

ip不可控,xff可控,带入到模版文件里,就形成了模版注入

看下版本号

image

因为比赛中允许联网(好评),所以查查对应的版本有没有0day

找到这两篇

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

第一篇是发现他必须自定义一个注册模版的类才可以插入payload,然而这个题里直接是sha1了一遍路径,所以打不了

http://www.tiaozhanziwo.com/archives/386.html

第二篇是过滤了php标签,所以无法直接命令执行

翻翻smarty手册

https://www.smarty.net/docs/zh_CN/language.function.include.php.tpl

发现可以用include看源码

然而不能跨目录看,就很鸡肋

image

继续翻手册看到一个eval标签

image

就rce了。。。

image

本来想直接system 来cat flag 结果是500没回显

猜想可能有函数禁用

找了一下确实是的,还有open basedir

image
image

写个shell

image

蚁剑连接

image

无法切换到根目录,需要bypass open basedir

image

蚁剑大法好,直接上大表哥的bypass disable function插件

image

拿到flag

image

手速慢,只拿了个三血

最后

嘲讽的是队友把我一直在看的这个ssrf做了,我把队友一直在看的smarty做了hhhh(队友tql企图当场挖框架0day)

这次比赛水的成绩还不错,见到了一堆巨佬

零食跟自助餐是真的好吃

可惜赶飞机没赶上比赛前一晚上的游艇观光,感觉损失一个亿

推荐阅读更多精彩内容