Before all
坑還好多,先放著當自己的memo和碎碎念,慢慢補完…
這幾天滾了一圈社區文章,發現自己對Java整個Web體系根本不熟…來開發吧XD
正在照這個複現一些有問題的功能並練習patch(主要還是先忙面試)
https://xz.aliyun.com/t/16232
https://xz.aliyun.com/t/16284
社區寶藏蠻多的XD
我最近看到很喜歡的設計:
From DEVCORE Wargame 2024: https://github.com/DEVCORE-Wargame/HITCON-2024/tree/main/challenges/Expressionism/
挖庫挖庫 >W<b
P.S. 初學Java開發 歡迎各位給我建議/指正我w
What, Why, How maven?
Maven是一個方便搭建web服務的一個專案,主要服務 Java,但也支援 C# 等其他語言的部署,只需提供架設檔(pom.xml)就會幫你把服務編譯/打包好,非常之方便~
pom.xml
我是使用spring boot server架設,是一個方便測試/打包的網頁框架!
結構長這樣(我知道還有很多,POM SPEC(Link)):
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
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId> <artifactId>javademo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>CTF JAVA WEB Demo</name> <description>A simple Spring Boot application in Java</description>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.3</version> <relativePath/> </parent>
</project>
|
在打滲透時可以特別注意dependencies中是否版本過舊,另外,TomCat 的 Credential 也可能存在pom.xml或者settings.xml中:
1 2 3 4 5 6 7
| <servers> <server> <id>TomcatServer</id> <username>tomcat</username> <password>password</password> </server> </servers>
|
Structure
Spring Boot架構大概長這樣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| . ├── pom.xml └── src └── main ├── java │ └── com │ └── example │ └── javademo │ ├── App.java │ └── MainController.java └── resources ├── static │ ├── test.txt │ └── wifu.gif └── templates └── index.html
|
pom.xml就是剛剛的結構,接下來src存source
main代表主結構,resources中的static與templates跟Flask一樣,分別是放靜態檔案及html模板
java資料夾內則是執行的程式碼,App.java跟MainController.java不是一定要這樣命名,但我覺得這比較能體現他們功能:
App.java
1 2 3 4 5 6 7 8 9 10 11 12
| package com.example.javademo;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
|
支撐整個 SpringApplication 並定義它(hint: 在java裡,主class必須跟檔名一樣)
而MainController一樣是Spring架設時會自己抓的,控制每個路由要幹嘛
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| package com.example.javademo;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.Map; import java.util.HashMap; import java.util.concurrent.atomic.AtomicReference;
import java.io.BufferedReader; import java.io.InputStreamReader;
@Controller public class MainController {
@GetMapping("/") @ResponseBody public String home() { return "Hello Whale!"; }
@GetMapping("/template") public String template(@RequestParam(value = "name", defaultValue = "Whale") String name, Model model) { model.addAttribute("name", name); return "index"; }
@GetMapping("/get") @ResponseBody public Map<String, String> getParams(@RequestParam Map<String, String> queryParams) { return queryParams; }
@PostMapping("/post") @ResponseBody public Map<String, String> postParams(@RequestBody Map<String, String> bodyParams) { return bodyParams; }
@GetMapping("/cmd") @ResponseBody public String executeCommand(@RequestParam(value = "cmd", defaultValue = "whoami") String cmd) { StringBuilder output = new StringBuilder(); try { Process process = Runtime.getRuntime().exec(cmd); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { output.append(line).append("<br>"); } } catch (Exception e) { return "<h1>Error: " + e.getMessage() + "</h1>"; } return "<h1>Execution Result:</h1><p>" + output + "</p>"; }
@RequestMapping(value = "/evaluate", method = RequestMethod.POST) @ResponseBody public String evaluate(@RequestParam(value = "id", defaultValue = "1+1") String id) {
ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext();
try { Object result = parser.parseExpression(id).getValue(context); return id+" = " + result; } catch (Exception e) { return "Error: Invalid Expression - " + e.getMessage(); } } }
|
如果有寫其他web app的經驗看應該會很快能點出每個地方在幹嘛(大同小異!):
@GetMapping
修飾符定義了路由,RequestMethod
@ResponseBody
則定義了純粹的回顯資料,對於有template的顯示是不需要的
@RequestParam
則是請求的parameters,預設跟常見的a=1&b=2
一樣,用parser取出,不過像我POST區就定義是Map<String, String>
,這時就必須以JSON請求
/cmd
路由示範了Java裡執行命令並回顯得方法
/evaluate
路由則示範了SPeL Injection的漏洞
小筆記:
1 2
| ${#request}的payload在注入jsp時可以獲得位置和一些敏感資訊 T(java.lang.Runtime).getRuntime().exec('curl localhost:9999/pwned'):基本RCE Chain
|
compile & run
Maven下載一樣走apt install
我是用spring boot,要先compile:
1 2
| mvn clean compile mvn spring-boot:run
|
提個外話
Tomcat
Structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 這個結構對於用maven, springboot架設jsp的網站有問題嗎 ├── pom.xml └── src └── main ├── java │ ├── Application.java │ └── JspController.java ├── resources │ └── messages.properties └── webapp └── WEB-INF ├── dispatcher-servlet.xml ├── views │ ├── application.properties │ └── index.jsp └── web.xml
|
dispatcher-servlet.xml(非必要)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="messages" /> </bean> </beans>
|
但可以方便定義一些內容
application.properties
1 2
| spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp
|
定義mvc應該怎麼渲染jsp files,而所謂的jsp就像這樣:
1 2 3 4 5 6 7
| <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head><title>Spring Boot JSP Example</title></head> <body> <h1><spring:message code="message.${name}" /></h1> </body> </html>
|
大致可理解成一個支援java表達,更靈活的html template
而上面其實就是一個SPeL Injection的範例
舉例來說,讀取訊息就可以像在src/main/resources/messages.properties寫入:
1
| message.whale=I'm flying and eating...
|
jsp讀取到message.whale就會顯示這段文字~