概要
loginとsignupがある、webサービス、adminの権限があると'date'コマンドを実行することができる flag.txtの中にflagがある、admin権限を取得し、flagの中身を見るコマンドを実行する必要がある。
まず、admin権限を取得していく
Writeup
def is_admin(self, email): user = self.db.get(email) if user is None: return False return user["email"] == "admin@cscg.de" and user["userid"] > 90000000
admin権限になるためにuseridが90000000以上かつ、emailが「admin@cscg.de」となっている
admin@cscs.deのemailの取得
userdb = UserDB("userdb.json") userdb.add_user("admin@cscg.de", 9_001_0001, str(uuid())) def api_create_account(data, user): if email == "admin@cscg.de": return error_msg("cant create admin") assert(len(groupid) == 3) assert(len(userid) == 4) userid = json.loads("1" + groupid + userid) if not check_activation_code(activation): return error_msg("Activation Code Wrong") print("activation passed") if userdb.add_user(email, userid, password): return success_msg("User Created") else: return error_msg("User creation failed") def check_activation_code(activation_code): # no bruteforce time.sleep(20) if "{:0>4}".format(random.randint(0, 10000)) in activation_code: return True else: return False
ユーザ作成時にActivation_codeに0から10000のランダム値が含まれていないと、ユーザの作成が行われない。
activate_codeには文字数制限やチェックが入っていないので、0000~9999までのすべての値を結合したものをactivatecodeとすることで通過できる。
loginが成功すると、ユーザのemailアドレスの変更と削除ができる。
adminデータの削除
def api_delete_account(data, user): if user is None: return error_msg("not logged in") if data["data"]["email"] != user["email"]: return error_msg("Hey thats not your email!") if delete_accs(data["data"].values()): return success_msg("deleted account") def delete_accs(emails): for email in emails: userdb.delete_user(email) return True
「if delete_accs(data["data"].values()):」.values()で値を指定しているため、{"data"{"email":"登録したユーザ"}, {"mail":"admin@cscg.de"}}とすることでadminのデータを消すことができる。
再度ユーザを作るり、ユーザの編集を行う。
def api_edit_account(data, user): if user is None: return error_msg("not logged in") new = data["data"]["email"] if userdb.change_user_mail(user["email"], new): return success_msg("Success") else: return error_msg("Fail")
edit_accountで「admin@cscg.de」にすることで、adminのemalを取得できた。
※同じ名前のemailを作れないため、一度adminのデータを削除する必要があった。
userid >90000000をクリアして完全にadmin権限を奪う
assert(len(groupid) == 3) assert(len(userid) == 4) userid = json.loads("1" + groupid + userid)
素直に考えるとMAXの値は 19999999で当然False
テストしまくった結果、9e9で9*109となり、useridの値をinfにすることができた
これでadmin権限を取得できた。
flagを取りに行く!
admin権限によって、linuxコマンドが実行できるようになる
def api_admin(data, user): if user is None: return error_msg("Not logged in") is_admin = userdb.is_admin(user["email"]) if not is_admin: return error_msg("User is not Admin") cmd = data["data"]["cmd"] # currently only "date" is supported if validate_command(cmd): out = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) return success_msg(out.stdout.decode()) def validate_command(string): return len(string) == 4 and string.index("date") == 0
要素数が4であり、dateから始まる必要がある。
これは、配列を使うことで解決できる。
cmd = ["date","--help","help","-help"]
len(cmd)は4であり、dateから始まるので問題ない。
しかし使用できる、コマンドはdateのみなので有用なオプションがないか探す。
-fオプションでファイルを指定できる。
これでFlagゲット。