2023kalmarctf
Invoiced
考点 审计代码 meta
元素实现跳转
先审计代码 先看orders路由如果是本地访问 并且cookie不存在bot的话会输出flag
然后看一下如何才能本地访问 继续看renderInvoice路由 我们发现可以向往页面里面插入元素
这里可以使用<meta>
标签来实现跳转 但是 时间要小于 await delay(1000) 那如何让本地去访问renderInvoice 这个路由呢看 checkout 这个路由 先绕过前面这个 if之后会执行到后面这个函数里面里面 pdf.renderPdf
这里它可以本地的去访问 renderInvoice 的路由 那如何要过前面的if呢 total * (1 - discountRate) 让他小于等于0就可以了
这样访问就可以了 可以去访问
虽然前面设置了cookie 但是localhost 不是和 127.0.0.1 不是同一个域名下的 所以 localhost 下的域名的cookie并不会带去127.0.0.1过去 所以 这个cookie判断是没有用的
[网鼎杯 2020 半决赛]BabyJS
主要的代码贴一下
var express = require('express');
var config = require('../config');
var url=require('url');
var child_process=require('child_process');
var fs=require('fs');
var request=require('request');
var router = express.Router();
var blacklist=['127.0.0.1.xip.io','::ffff:127.0.0.1','127.0.0.1','0','localhost','0.0.0.0','[::1]','::1'];
router.get('/debug', function(req, res, next) {
console.log(req.ip);
if(blacklist.indexOf(req.ip)!=-1){
console.log('res');
var u=req.query.url.replace(/[\"\']/ig,'');
console.log(url.parse(u).href);
let log=`echo '${url.parse(u).href}'>>/tmp/log`;
console.log(log);
child_process.exec(log);
res.json({data:fs.readFileSync('/tmp/log').toString()});
}else{
res.json({});
}
});
router.post('/debug', function(req, res, next) {
console.log(req.body);
if(req.body.url !== undefined) {
var u = req.body.url;
var urlObject=url.parse(u);
if(blacklist.indexOf(urlObject.hostname) == -1){
var dest=urlObject.href;
request(dest,(err,result,body)=>{
res.json(body);
})
}
else{
res.json([]);
}
}
});
module.exports = router;
先看get /debug路由 先禁止了一些本地ip的形式 然后 又判断是不是本地访问的 然后有吧 单引号和双引号替换为空了 然后把herf 写进了 /tmp/log
看 post /debug 接受一个url的参数 然后判断hostname是否又本地ip 没有i的话就使用rquest 包发送一个请求
现在发现利用点是写入我们的 url 到 /tmp/log 然后输出 /tmp/log
现在一种简单的方法就是 把/flag 覆盖到/tmp/log里面 然后输出 log文件 先看第一步 如何绕过黑名单 ssrf 这里可以通过0177.0.0.1
来进行ssrf ssrf之后我们就可以写入文件了 那现在就是需要闭合 let log=
echo '${url.parse(u).href}'>>/tmp/log;
echo 然后写我们想要的内容了
本地测试
但是这里过滤了单引号 可以使用二次编码来绕过 为什么可以二次编码来绕过呢 调式看一下
一直到发送request请求的时候还是二次编码一次都没有解码
然后到执行这个 request请求的时候 就解码一次
然后 到url.parse的时候再解码一次
这个时候就成功的闭合单引号了 再说一下为什么后面要是%00 被认为是字符串截止 会把后面的 >>/tmp/log截取掉 最后成功覆盖log文件
[HarekazeCTF2019]encode_and_encode
<?php
error_reporting(0);
if (isset($_GET['source'])) {
show_source(__FILE__);
exit();
}
function is_valid($str) {
$banword = [
// no path traversal
'\.\.',
// no stream wrapper
'(php|file|glob|data|tp|zip|zlib|phar):',
// no data exfiltration
'flag'
];
$regexp = '/' . implode('|', $banword) . '/i';
if (preg_match($regexp, $str)) {
return false;
}
return true;
}
//$body = file_get_contents('php://input');
$body='{"page":"\u0070\u0068\u0070\u003A\u002F\u002F\u0066\u0069\u006C\u0074\u0065\u0072\u002F\u0063\u006F\u006E\u0076\u0065\u0072\u0074\u002E\u0062\u0061\u0073\u0065\u0036\u0034\u002D\u0065\u006E\u0063\u006F\u0064\u0065\u002F\u0072\u0065\u0073\u006F\u0075\u0072\u0063\u0065\u003D\u002F\u0066\u006C\u0061\u0067"}';
;
$json = json_decode($body, true);
if (is_valid($body) && isset($json) && isset($json['page'])) {
$page = $json['page'];
$content = file_get_contents($page);
if (!$content || !is_valid($content)) {
$content = "<p>not found</p>\n";
}
} else {
$content = '<p>invalid request</p>';
}
// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content);
echo json_encode(['content' => $content]);
一个小tirck把
json_decode的时候会把unicode编码的字符解码一次 从而我们可以是body绕过正则
然后后面又因为过滤了flag的格式 直接用base64编码的形式输出
标签:tmp,log,url,res,req,var,nodes From: https://www.cnblogs.com/kkkkl/p/17206744.html