前言

昨天晚上在逛Freebuf的时候,发现了一个很有趣的帖子,通过图片加载来执行php的脚本,进而获得用户的IP,感觉很有意思,于是准备复现一下。具体的文章是来自Freebuf的《技术讨论 | 看我如何通过邮箱获取IP定位》

正文

1 检测邮件是否已读

1.1 创建PHP文件

我们这里直接创建一个php的图片吧,代码也是用的freebuf里面的,如下:

<html>
	<head>
  		<title>PHP 测试</title>
 	</head>
	<body>
		<?php
		header('Content-Type:image/png');
		$im = imagecreatetruecolor (1,1);
		$background_color = imagecolorallocatealpha($im, 255, 255, 255, 127);
		imagepng($im);
		imagedestroy($im);
		?>
	</body>
</html>

直接将代码储存为index.php文件,然后通过地址访问;通过这个代码,我们创建了一个1x1的全透明图片,然后将他放在服务器上面,然后看一下效果:
16484743861.png

1.2 创建get_ip()函数

我们直接把以下代码,加入到<?php ?>之中:

function get_ip()
{
    static $ipFrom = ['HTTP_CLIENT_IP','HTTP_X_FORWARDED_FOR','HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP','HTTP_FORWARDED_FOR','HTTP_FORWARDED','REMOTE_ADDR'];
    foreach ($ipFrom as $key) {
        if (array_key_exists($key, $_SERVER)) {
            foreach (explode(',', $_SERVER[$key]) as $ip) {
                $ip = trim($ip);
                if ((bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    return $ip;
                }
            }
        }
    }
    return  '127.0.0.1';
}

1.3 连接数据库,插入数据

我们构造了get_ip()方法之后,我们获得了对方的数据,这样我们可以直接通过SQL插入到数据库之中就可以了

# user's data
$ip = get_ip();
$from = $_SERVER['HTTP_REFERER'];
$client = $_SERVER['HTTP_USER_AGENT'];

# connect to MySQL


这里遇到一个坑,发现无论怎么样都无法连上sql数据库,而且虽然可以发现F12浏览器Network选项里面返回了500,但是也不返回任何错误,一片空白
16484815881.png
16484813781.png
我们发现如果需要PHP返回信息,需要修改一下php.ini这个配置文件,参考来自php 服务器500错误解决;我们追踪发现我们的php.ini文件的储存位置在/etc/php/7.2/apache2/php.ini这个目录,根据上述参考文章,我们需要修改的值是两个:

  1. display_errors = On
  2. error_reporting = E_ALL | E_STRICT

分别改动:
16484816501.png

重启服务,通过命令service apache2 restart,终于发现问题所在,Access denied。
16484817261.png

最终还是没有在这个服务器解决,具体的原因未知,于是将有可能的错误导致原因列在下方:

  1. 原因1:如何解决PHP连接MySQL时出现的Access denied for user 'root' @ 'localhost'(using password :YES)
  2. 原因2:MySQL登录时出现Access denied for user ‘root‘@‘localhost‘ (using password: YES)无法打开的解决方法

最终打算奔赴阿里云,创建一个现成的LAMP7.4。/(ㄒoㄒ)/~~
16484845581.png

于是乎,在奔赴阿里云后,终于解决,最终代码如下:

<html>
<head>
  <title>PHP 测试</title>
</head>
<body>
<?php

# make it an image
header('Content-Type:image/png');
$im = imagecreatetruecolor (1,1);
$background_color = imagecolorallocatealpha($im, 255, 255, 255, 127);
imagepng($im);
imagedestroy($im);

# get values by get_ip() and varaible $_SERVER
$ip = get_ip();
$timestamp = $_SERVER["REQUEST_TIME"];
$useragent = $_SERVER["HTTP_USER_AGENT"];

# config for MySQL database
$config = parse_ini_file(realpath(dirname(__FILE__) . '/config/config.ini'));
$servername = $config['servername'];
$username = $config['username'];
$password = $config['password'];
$dbname = $config['dbname'];

# create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);

# detect whether connect
if (!$conn) {
    die("Connection failed: " . mysqli_connect_error());
}

# insert records to database
$sql = "INSERT INTO ip (ip, timestamp, useragent) VALUES ('". $ip ."', '". $timestamp  ."', '". $useragent  ."')";
if ($conn->query($sql) === TRUE) {
    echo "新记录插入成功";
} else {
    echo "Error: " . $sql . "<br>" . $conn->error;
}

# close connection
mysqli_close($conn);

# function for get_ip()
function get_ip()
{
    static $ipFrom = ['HTTP_CLIENT_IP','HTTP_X_FORWARDED_FOR','HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP','HTTP_FORWARDED_FOR','HTTP_FORWARDED','REMOTE_ADDR'];
    foreach ($ipFrom as $key) {
        if (array_key_exists($key, $_SERVER)) {
            foreach (explode(',', $_SERVER[$key]) as $ip) {
                $ip = trim($ip);
                if ((bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    return $ip;
                }
            }
        }
    }
    return  '127.0.0.1';
}
?>
</body>
</html>

有点累,这个PHP和MySQL连接有点迷,但是无论如何终于做好了。然后我们为了方便和具有一定迷惑性,还能制作一个短链接,短链接制作地址
16484904511.png
后来发现成功记录~!
16484905061.png
我们为我们1x1图片生成的短链接为 https://reurl.cc/xOrnQ4

1.4 测试各大邮箱

对于测试各种邮箱是否会中招,我们只需要将我们生成的短链接作为图片插入即可。

1.4.1 QQ邮箱 -> QQ邮箱

QQ邮箱发QQ邮箱并没有自动加载
16484907241.png
16484908001.png
16484908371.png

1.4.2 126邮箱 -> 126邮箱

126邮箱发126邮箱也并没有自动加载
16484909161.png
16484909641.png
16484909791.png

1.4.3 163邮箱 -> 163邮箱

163邮箱发163邮箱并没有自动加载
16484911661.png
16484913071.png
16484912931.png

1.4.4 163邮箱 -> QQ邮箱

163邮箱发QQ邮箱也没有自动加载,手机端也没有
16484914141.png

1.5 总结

可想而知, 0.0 还是蛮安全的,看了有不少人说163可以发,163->QQ也可以,但是实际测试了一下,并不可以。也可能因为是2018年的东西了,4年前的东西,大概早就已经修复了吧。(笑。

参考

[1] 技术讨论 | 看我如何通过邮箱获取IP定位
[2] php 服务器500错误解决
[3] 如何解决PHP连接MySQL时出现的Access denied for user 'root' @ 'localhost'(using password :YES)
[4] MySQL登录时出现Access denied for user ‘root‘@‘localhost‘ (using password: YES)无法打开的解决方法

Q.E.D.


立志做一个有趣的碳水化合物