# HSCCTF-2024 Writeup
# 前言
别的方向没怎么看,单看 Re 感觉质量有待提高吧
# Misc[1/8]
# SIGN_IN
先从 jpg 里提取一张图片,得到 HAPPY_NEW_YEAR
,然后用 outguess 得到 flag
# Crypto[1/8]
# FUNNY
题目下下来跑一下就出 flag 了...
# CheckIn[1/1]
# CHECKIN
关注两个公众号
# Re[6/6]
# TEA
朴实无华的 tea
#include <stdio.h> | |
#include <stdint.h> | |
void decrypt(uint32_t *v, uint32_t *k) | |
{ | |
uint32_t v0 = v[0], v1 = v[1], i; | |
uint32_t delta = 0x9e3779b9; | |
uint32_t sum = delta * 32; | |
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; | |
for (i = 0; i < 32; i++) | |
{ | |
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); | |
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); | |
sum -= delta; | |
} | |
v[0] = v0; v[1] = v1; | |
} | |
int main() | |
{ | |
uint32_t key[] = {2, 2, 3 ,4}; | |
uint32_t enc[] = {0xb805d767, 0x63c174c3}; | |
decrypt(enc, key); | |
for (size_t i = 0; i < 2; i++) | |
printf("%x ", enc[i]); | |
} |
# ROULETTE
简单扫一眼逻辑,发现在 sub_A5870
下的 return sub_9D0F3();
就是调用解密函数的地方
那么就直接调试,改 eip 直接飞过去就好啦
HSCCTF{H31L0_My_FR13ND!}
# THE_WOLF_SONG
没啥难度,就一个 rc4 然后异或来异或去
#include <stdio.h> | |
#include <string.h> | |
void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) | |
{ | |
int i = 0, j = 0; | |
char k[256] = {0}; | |
unsigned char tmp = 0; | |
for (i = 0; i < 256; i++) | |
{ | |
s[i] = i; | |
k[i] = key[i % Len]; | |
} | |
for (i = 0; i < 256; i++) | |
{ | |
j = (j + s[i] + k[i]) % 256; | |
tmp = s[i]; | |
s[i] = s[j]; | |
s[j] = tmp; | |
} | |
} | |
void rc4_crypt(unsigned char *s, unsigned char *data, unsigned long Len) | |
{ | |
int i = 0, j = 0, t = 0; | |
unsigned long k = 0; | |
unsigned char tmp; | |
for (k = 0; k < Len; k++) | |
{ | |
i = (i + 1) % 256; | |
j = (j + s[i]) % 256; | |
tmp = s[i]; | |
s[i] = s[j]; | |
s[j] = tmp; | |
t = (s[i] + s[j]) % 256; | |
data[k] ^= s[t]; | |
} | |
} | |
unsigned char enc[] = { | |
0xce, 0x26, 0x9c, 0x7, 0x48, 0xd9, 0xfd, 0x23, 0xba, 0x9a, | |
0x40, 0xa8, 0x2e, 0xbd, 0xfc, 0x77, 0xb7, 0x5d, 0x7e, 0x67, | |
0x99, 0xfd, 0xcd, 0x63, 0x13, 0xa, 0x94, 0x5b, 0x95, 0x2c, | |
0x26, 0x60, 0x1e, 0x1e, 0xb4, 0x30, 0x89, 0xcf, 0xef, 0x68 | |
}; | |
unsigned char *key = "HSCCTF{FAKE_FLAG!}"; | |
int main() | |
{ | |
for (size_t i = 0; i < 40; i++) | |
enc[i] ^= i; | |
for (size_t i = 0; i < strlen(key) - 1; i++) | |
enc[i] ^= key[i + 1]; | |
for (size_t i = 0; i < strlen(key); i++) | |
enc[i] ^= key[i]; | |
for (size_t i = 0; i < 40; i++) | |
enc[i] ^= i; | |
unsigned char s[256] = {0}; | |
rc4_init(s, key, strlen(key)); | |
rc4_crypt(s, enc, 40); | |
for (size_t i = 0; i < 40; i++) | |
enc[i] ^= 3; | |
for (size_t i = 0; i < 40; i++) | |
enc[i] ^= 6; | |
for (size_t i = 0; i < 40; i++) | |
printf("%c", enc[i]); | |
} |
HSCCTF{Welcome_To_Participate_In_HSCCTF}
# NO_PY
BeginCTF2024 的原题,直接贴 exp 了
from gmssl import sm4 | |
import base64 | |
key = list('Please_Do_not_py') | |
key = "".join([chr(ord(i) ^ 102) for i in key]) | |
enc = 'YJ+70VWYioYm3EhF6qdScVXBpCdPm+hCS/HP+Gj421RyxkZbwzni7o2zGG/Mis4Wr6sbXYr4ufnKwQk7vrG8yA==' | |
def pad_pkcs7(data): | |
'''PKCS#7填充''' | |
padding_len = 16 - len(data) % 16 | |
padding = bytes([ | |
padding_len] * padding_len) | |
return data + padding | |
def unpad_pkcs7(padded_data): | |
'''PKCS#7去填充''' | |
padding_len = padded_data[-1] | |
return padded_data[:-padding_len] | |
class SM4: | |
def __init__(self): | |
self.gmsm4 = sm4.CryptSM4() | |
def encryptSM4(self, encrypt_key, value): | |
gmsm4 = self.gmsm4 | |
gmsm4.set_key(encrypt_key.encode(), sm4.SM4_ENCRYPT) | |
padded_value = pad_pkcs7(value.encode()) | |
encrypt_value = gmsm4.crypt_ecb(padded_value) | |
return base64.b64encode(encrypt_value) | |
def decryptSM4(self, key, value): | |
data = base64.b64decode(value) | |
gmsm4 = self.gmsm4 | |
gmsm4.set_key(key.encode(), sm4.SM4_DECRYPT) | |
decrypt_value = gmsm4.crypt_ecb(data) | |
return decrypt_value | |
s = SM4() | |
flag = s.decryptSM4(key, enc) | |
print(unpad_pkcs7(flag).decode()) |
flag{Pay_M0re_@ttention_to_th3_key!!}
# VM_RE
简单的 vm,动调分析一下看看,实际上就用了仨指令
相当于 (input[i] + 0xA) ^ 0x33
0x39 mov | |
0x4D add | |
0x26 xor | |
; mov | |
opcode = a1; | |
reg_4 = a1[e_ip + 1]; | |
e_ip += 2; | |
chr = reg_4; | |
; add | |
opcode = a1; | |
reg_4 += a1[e_ip + 1]; | |
e_ip += 2; | |
chr = reg_4; | |
; xor | |
opcode = a1; | |
reg_4 ^= a1[e_ip + 1]; | |
e_ip += 2; | |
chr = reg_4; |
直接解就好了
#include <stdio.h> | |
#include <stdint.h> | |
int main() | |
{ | |
uint32_t enc[9]; | |
enc[0] = 0x42584543; | |
enc[1] = 0xF4E58B6; | |
enc[2] = 0x70B37143; | |
enc[3] = 0x72735D4E; | |
enc[4] = 0x5E700E0F; | |
enc[5] = 0x5D0C4E72; | |
enc[6] = 0x8097071; | |
enc[7] = 0x5D73725D; | |
enc[8] = 0x39B4; | |
for (size_t i = 0; i < 34; i++) | |
{ | |
printf("%c", ((*((char*)enc + i)) & 0xff ^ 0x33) - 10); | |
} | |
} |
# ANDROID
分析一下 java 层,读取一个图片的数据,然后调用 native 函数,传入输入的内容和图片数据
分析一下 so 层,图片数据使用 murmur3_32 哈希算法,得到一个 32 字节的哈希,作为 key
encode_fun
是 SM4,key 的前 16 字节加密前 16 个字节的数据,后面 16 个字节加密后面 16 字节的数据
先 frida hook 一下 murmur3_32 的返回值拿个 key
var func_addr = Module.findExportByName("libmidand.so" , "_Z10murmur3_32PKcjj"); | |
console.log("func addr is ---" + func_addr); | |
Interceptor.attach(func_addr, { | |
onLeave: function(args){ | |
console.log("enter murmur3_32 retvalue->\n" + hexdump(args)); | |
} | |
}); | |
/* | |
func addr is ---0x7f134457ae40 | |
[PGJM10::midand ]-> enter murmur3_32 retvalue-> | |
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF | |
7f13c97b0d00 c4 83 84 72 b8 e1 60 ba 5d 99 5a 6b e3 67 40 17 ...r..`.].Zk.g@. | |
7f13c97b0d10 7c 3f 33 21 91 1c fa 54 8f 35 30 73 dd 2b 80 a7 |?3!...T.50s.+.. | |
*/ |
直接解密就好啦
from gmssl import sm4 | |
enc = bytearray.fromhex("731E133EF76A5CD1EF9626A9947CF4A46CE237B70D4905E921E35E2E7D7A1A74") | |
""" | |
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF | |
7f13c97b0d00 c4 83 84 72 b8 e1 60 ba 5d 99 5a 6b e3 67 40 17 ...r..`.].Zk.g@. | |
7f13c97b0d10 7c 3f 33 21 91 1c fa 54 8f 35 30 73 dd 2b 80 a7 |?3!...T.50s.+.. | |
""" | |
key1 = bytearray.fromhex("c4838472b8e160ba5d995a6be3674017") | |
key2 = bytearray.fromhex("7c3f3321911cfa548f353073dd2b80a7") | |
s = sm4.CryptSM4(padding_mode=sm4.zero_padding) | |
s.set_key(key1, sm4.SM4_DECRYPT) | |
dec = s.crypt_ecb(enc[:16]) | |
print(dec.decode(), end="") | |
s.set_key(key2, sm4.SM4_DECRYPT) | |
dec = s.crypt_ecb(enc[16:]) | |
print(dec.decode(), end="") |
flag{fad1c7e27ec411eebe3a3e4419a1b3cc}
# BlockChain[1/1]
# BONUS
题目要求让余额为 1,看一眼合约,整型溢出漏洞,余额类型为 uint256, 2^256+1
就可以溢出到 1 了
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.7.0; | |
contract VipCard { | |
mapping(address => uint) public balances; | |
function applyCard() public { | |
balances[msg.sender] = 114514; | |
} | |
function topUp(uint _amount) public { | |
balances[msg.sender] += _amount; | |
} | |
function buyCandy() public { | |
require(balances[msg.sender] > 0, "not sufficient funds"); | |
balances[msg.sender] -= 1; | |
} | |
} |