The Finals of Midnight Sun CTF 2023 was held in August 19th and 20th in Stockholm, Sweden. I played the CTF as a member of TokyoWesterns and we stood 2nd place.
2023年午夜太阳CTF总决赛于8月19日至20日在瑞典斯德哥尔摩举行。我作为东京西部片的成员参加了CTF,我们获得了第二名。
Midnight Sun this year had both CTF and conference.
今年的午夜太阳既有CTF又有会议。
The hotel and venue this year was great. Both were very close to the station :+1:
今年的酒店和场地都很棒。两者都非常靠近车站:+1:
Writeup 写起来
The challenge files and my solvers are available here:
挑战文件和我的求解器可在此处获得:
[Pwn] guessboy [Pwn] 猜猜男孩
Guessboy is a gameboy pwn challenge. We’re distributed a gameboy ROM file. Once we solve the challenge, we need to call the organizer to get the physical gameboy which contains the real flag.
Guessboy是一个gameboy pwn挑战。我们分发了一个gameboy ROM文件。一旦我们解决了挑战,我们需要打电话给组织者以获得包含真实标志的物理游戏男孩。
The game is not actually a game, but looks like a calculator:
游戏实际上不是游戏,而是看起来像一个计算器:
Actually I saw a similar challenge in Midnight Sun CTF 2019 Finals, which I couldn’t solve at the time. According to the challenge author, however, the exploit of the challenge is different this time.
实际上,我在午夜太阳CTF 2019总决赛中看到了类似的挑战,当时我无法解决。然而,根据挑战作者的说法,这次挑战的利用是不同的。
Still, I remembered the vulnerability was stack buffer overflow. The same bug exists in this challenge.
不过,我记得这个漏洞是堆栈缓冲区溢出。此挑战中存在相同的错误。
The result of a calculation is pushed to the stack. If we hit the equals (=) key, the result is pushed to the stack and the stack top increments (decrements in the memory stack). Since there is no limit on the stack top, we can easily overflow the buffer. However, you will get a crash message if you randomly overflow the buffer.
计算结果将推送到堆栈。如果我们按下等于 (=) 键,结果将被推送到堆栈,堆栈顶部递增(内存堆栈中的递减)。由于堆栈顶部没有限制,我们可以轻松地使缓冲区溢出。但是,如果随机溢出缓冲区,则会收到崩溃消息。
So, there is a stack canary. The stack canary is a fixed value and you can analyse the ROM to get the correct value: 0x5858. This value is also the same as that of 2019.
所以,有一个堆栈金丝雀。堆栈金丝雀是一个固定值,您可以分析 ROM 以获得正确的值:0x5858。该值也与2019年相同。
The pwn part is over. The remaining part is reversing. Since we don’t know where is the flag, we don’t know what to do. @n4nu reversed the binary and guessed that:
pwn 部分结束了。其余部分正在反转。由于我们不知道标志在哪里,所以我们不知道该怎么办。 @n4nu颠倒了二进制并猜测:
- There is a function that draws a scrambled flag on the display.
有一个功能可以在显示屏上绘制加扰的标志。 - The flag image exists in tiles.
标志图像存在于磁贴中。 - The flag is scrambled because of a wrong argument passed to the draw function.
由于传递给 draw 函数的错误参数,该标志被打乱。
We had to load the tiles and draw it with a right parameter. Here is the ROP chain to accomplish it:
我们必须加载瓷砖并使用正确的参数绘制它。这是完成它的 ROP 链:
22616 = = = = = = = = = C ; stack canary (0x5858) 20450 = C ; func1 (0x4fe2) 10596 = C ; skip (0x2964) 65280 = C ; arg1 (0xff00) 7330 = C ; arg2 (0x1ca2) 20699 = C ; func2 (0x50db) 464 = C ; loop (0x1d0) 0 = C ; arg1 (0x0) 4628 = C ; arg2 (0x1214) 6970 = Q ; arg3 (0x1b3a)
[Pwn] HFSAntiCheat [pwn]HFSAntiCheat
A vagrant environment, Windows kernel driver, and client to submit the exploit are given. It was the first time to solve Windows kernel challenge in a CTF. I leaned a lot but also wasted a lot of time because of the different behavior between vagrant and my virtual box 😥
给出了一个流浪环境、Windows 内核驱动程序和提交漏洞的客户端。这是第一次在CTF中解决Windows内核挑战。我倾斜了很多,但也浪费了很多时间,因为流浪者和我的虚拟盒子之间的行为不同:cry:
While I was absent for 1v1pwn, @n4nu finished analysing the binary. The driver registers a device and a notifier routine for process creation.
当我缺席 1v1pwn 时,@n4nu完成了二进制分析。驱动程序注册用于进程创建的设备和通知程序例程。
When a process is created with its name set to “CHEAT”, the driver checks if the PE imports some blacklisted Windows APIs. However, this routine was not related to the exploit at all.
创建名称设置为“CHEAT”的进程时,驱动程序会检查 PE 是否导入某些列入黑名单的 Windows API。但是,此例程与漏洞利用完全无关。
The important feature is the device I/O control. The driver accepts two requests that directly reads from and writes to the physical memory. We have full control over the entire physical memory.
重要功能是设备 I/O 控制。驱动程序接受两个直接读取和写入物理内存的请求。我们可以完全控制整个物理内存。
My first idea was:
我的第一个想法是:
- Leak the base address of
ntoskrnl.exe
.
泄漏 的ntoskrnl.exe
基址。 - Read the pointer at
HalDispatchTable+0x8
, which points toNtQueryIntervalProfile
.
读取指向HalDispatchTable+0x8
的NtQueryIntervalProfile
指针。 - Overwrite the machine code of
NtQueryIntervalProfile
with our shellcode.
用我们的外壳代码覆盖机器NtQueryIntervalProfile
代码。 - Call
NtQueryIntervalProfile
to escalate privilege.
呼叫NtQueryIntervalProfile
以提升权限。
It worked fine on my VirtualBox environment. However, it didn’t work on the distributed vagrant environment. I wrote “virtual to physical” address converter but it didn’t work well on vagrant. If anyone is familiar with page table, please check my exploit and tell me what is wrong.
它在我的VirtualBox环境中工作正常。但是,它不适用于分布式流浪环境。我写了“虚拟到物理”地址转换器,但它在流浪汉身上效果不佳。如果有人熟悉页表,请检查我的漏洞并告诉我出了什么问题。
Eventually I couldn’t fix the bug, and I changed the exploit 1h before the end of the CTF:
最终我无法修复该错误,我在 CTF 结束前 1 小时更改了漏洞:
- Search memory for the machine code of
NtQueryIntervalProfile
.
在内存中搜索 的NtQueryIntervalProfile
机器代码。 - Overwrite the machine code with our shellcode.
用我们的外壳代码覆盖机器代码。 - Call
NtQueryIntervalProfile
to escalate privilege.
呼叫NtQueryIntervalProfile
以提升权限。
I avoided searching memory because there was a 5-second time limit, and it is not usually stable. However, this is CTF. Faster solve is better than a beautiful exploit.
我避免搜索内存,因为有 5 秒的时间限制,而且它通常不稳定。然而,这是CTF。 更快的求解胜过漂亮的漏洞利用。
I should’ve solved this challenge much faster…
我应该更快地解决这个挑战……
[Crypto] speed-manifesto
[加密]速度宣言
This is a speed-run challenge. We had to solve speed-run challenges within 3rd blood to get advantage. 200 points for 1st blood, 150 for 2nd, 100 for 3rd, and 50 for the rest.
这是一个快速运行的挑战。我们必须解决第三血速跑的挑战才能获得优势。第一血200分,第二血150分,第三血100分,其余50分。
The distributed archive contains a lot of text files like this:
分布式存档包含许多文本文件,如下所示:
Public Exponent: 65537 Modulus: 8183083614123980651512525726265039763297170592399337374069708919926046325913623412792726783191923340532116587489748386113782581259412232424196738634940809 Ciphertext: b'(\xa6\xc0\xee\xb5\x9d\xd2\xc8\xe6\xa1\xb1\xcf:\x8b\xdcgx\xef\xb4\t\x7fvM@\xc8\x98\xbd\x80\xad\x13\x11\xeb\x97\xef\xc84\xd6|\x93E@\xeb\xc9\xf9\x0b\x86\xc7\x8bpKV\xe8\xa1\xa4&X\x14\\\x1a\xe3\x13\x8d\x8d6'
I guessed there would be modulus which uses the same prime. I wrote a script to take GCD of each modulus and found two files shared the same modulus with different Es.
我猜会有模量使用相同的素数。我编写了一个脚本来获取每个模数的GCD,发现两个文件共享具有不同E的相同模数。
Public Exponent: 81527149853274967867330281122861369134002594020874386569175070591393763589124283222257680735360206160019714178475186119840676412580184783642914952823718854196285068193471576875760518418570508606597801241354462995303092313113267959493950020688558073609011113475992265891863855436963447737070556709073024059749 Modulus: 105485909539302343682393765142198393869888400422595584344848080319220554344765142068633113057605072008120447995511459791164086717714452445525900872135444441922799547203637125587718326496756865379111734536835717969217501986460486866455030114291836448819270922526967276362623954616008938297593516881809069452459 Ciphertext: b"\x0c\x01\x8b\x84\x02P\x80_A\x1c|\x1f\xd7\xafP\xf7\x14\xb3\x1b\xb4\xcb\x90)\x1f\x1d/\xe0\\\x861Y]+7}\x97\xec\x9b^B\x1b\xc76\xc4 kb'\xaa\xda\xbf\x95\xeaP\x0b5\xb9Z\x7f\xe6C\xb2H.v\x18:ga\xee\xd7=}\xfb\xda\xbd\xee\xa8\x82\xf2\xc2\x1c6\\}\xd7\x005AW\xc0*hRNZ\x86\xfa\x80\xcb\t8\xbe9ad2}\x84\x82\xf2\x88h\x87\x85\xcb\x00E\xb4\xae\xb9\xd1\x15g\xbe\x18!\x8e"
Public Exponent: 90051294818134602141342465972381725307723336343068630953802954374926328987011486242807231248352006000143918922842329124501936958773012452561039323344339325165614434298436842264587505847772729164638758139465380776251275917722434711009950711165155879895556773415263339750741308013278846283398286170778381488987 Modulus: 105485909539302343682393765142198393869888400422595584344848080319220554344765142068633113057605072008120447995511459791164086717714452445525900872135444441922799547203637125587718326496756865379111734536835717969217501986460486866455030114291836448819270922526967276362623954616008938297593516881809069452459 Ciphertext: b'\x03[\xb4\xb0\x08\xde\x8b\xf9\xf4{\x04\xc8\x9c7\xc2\x84\x1f\x8e\xd4\xd0\x9f\xf4H\xe3(|\xbb\xf5N\xd9~\xbe\x13\xb8\xf5\x1a\xe8\xe21\xc2\xf2D\xb3D\x8a\n)\x14\xe2R\xad\x97\xbe\xcf\n\x1b\xf5I\xad\xf7s\x1d\xfbzq\x17\xa9\x80\xf0\xc6\xb0\x80y\xb9\x7f\xbe\xd0a~\xdf+:\xaa\x05=\xdb\x12"\xb5\x16\x1d\xb6\x12\xd5\xa5i\x9f\x19\xd3\xba\xc4\x11\x19\x9b\xd3\n\x81o\xc0\x9c\xcc\xebE{\xc5\x15\xdd\x92\xefq!h\xee\xb4\x16\x9a\xe4\xb5'
Common modulus attack. 普通模量攻击。
2nd blood –> 150 points
第二滴血–>150分
[Pwn] speed-pwn [pwn] speed-pwn
Yet another speedrun challenge.
又是一个速度奔跑的挑战。
The program runs the following command:
程序运行以下命令:
system("$PROG '<arbitrary string>'");
where $PROG
is set to /bin/echo
.
其中 $PROG
设置为 /bin/echo
。
The input is vulnerable to stack buffer overflow.
输入容易受到堆栈缓冲区溢出的影响。
My idea is to overwrite the array of environment variables with the pointer to “PROG=sh”.
我的想法是用指向“PROG=sh”的指针覆盖环境变量数组。
2nd blood –> 150 points
第二滴血–>150分
原文始发于hatenablog:Midnight Sun CTF 2023 Finals – Writeups – CTFするぞ